Feature Tip: Add private address tag to any address under My Name Tag !
More Info
Private Name Tags
ContractCreator
Latest 25 from a total of 681 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Get Reward | 21149118 | 71 days ago | IN | 0 ETH | 0.004472 | ||||
Get Reward | 21034639 | 87 days ago | IN | 0 ETH | 0.00399975 | ||||
Sync | 20602366 | 147 days ago | IN | 0 ETH | 0.00025309 | ||||
Get Reward | 20557470 | 154 days ago | IN | 0 ETH | 0.00090366 | ||||
Sync | 20530680 | 157 days ago | IN | 0 ETH | 0.00027796 | ||||
Get Reward | 20525383 | 158 days ago | IN | 0 ETH | 0.00060663 | ||||
Get Reward | 20504811 | 161 days ago | IN | 0 ETH | 0.00072365 | ||||
Get Reward | 19825383 | 256 days ago | IN | 0 ETH | 0.00200286 | ||||
Get Reward | 19794960 | 260 days ago | IN | 0 ETH | 0.00233072 | ||||
Sync | 19756508 | 265 days ago | IN | 0 ETH | 0.00132027 | ||||
Get Reward | 19650002 | 280 days ago | IN | 0 ETH | 0.01149041 | ||||
Withdraw Locked | 19602803 | 287 days ago | IN | 0 ETH | 0.00525555 | ||||
Get Reward | 19602798 | 287 days ago | IN | 0 ETH | 0.0065813 | ||||
Get Reward | 19451125 | 308 days ago | IN | 0 ETH | 0.01167655 | ||||
Get Reward | 19231458 | 339 days ago | IN | 0 ETH | 0.00763401 | ||||
Withdraw Locked | 19181252 | 346 days ago | IN | 0 ETH | 0.0198131 | ||||
Get Reward | 19105857 | 357 days ago | IN | 0 ETH | 0.00639984 | ||||
Sync | 19073532 | 361 days ago | IN | 0 ETH | 0.00107363 | ||||
Get Reward | 19071269 | 362 days ago | IN | 0 ETH | 0.00492885 | ||||
Get Reward | 19068995 | 362 days ago | IN | 0 ETH | 0.00411119 | ||||
Get Reward | 19058296 | 363 days ago | IN | 0 ETH | 0.00437401 | ||||
Get Reward | 18940205 | 380 days ago | IN | 0 ETH | 0.00749603 | ||||
Get Reward | 18896211 | 386 days ago | IN | 0 ETH | 0.0046274 | ||||
Get Reward | 18891594 | 387 days ago | IN | 0 ETH | 0.00868672 | ||||
Get Reward | 18685819 | 416 days ago | IN | 0 ETH | 0.02237887 |
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Contract Name:
FraxUnifiedFarm_ERC20_Vesper_Orbit_FRAX
Compiler Version
v0.8.10+commit.fc410830
Contract Source Code (Solidity)
/** *Submitted for verification at Etherscan.io on 2022-02-03 */ // SPDX-License-Identifier: GPL-2.0-or-later pragma solidity >=0.8.0; // Sources flattened with hardhat v2.8.3 https://hardhat.org // File contracts/Math/Math.sol /** * @dev Standard math utilities missing in the Solidity language. */ library Math { /** * @dev Returns the largest of two numbers. */ function max(uint256 a, uint256 b) internal pure returns (uint256) { return a >= b ? a : b; } /** * @dev Returns the smallest of two numbers. */ function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } /** * @dev Returns the average of two numbers. The result is rounded towards * zero. */ function average(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b) / 2 can overflow, so we distribute return (a / 2) + (b / 2) + ((a % 2 + b % 2) / 2); } // babylonian method (https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method) function sqrt(uint y) internal pure returns (uint z) { if (y > 3) { z = y; uint x = y / 2 + 1; while (x < z) { z = x; x = (y / x + x) / 2; } } else if (y != 0) { z = 1; } } } // File contracts/Curve/IveFXS.sol pragma abicoder v2; interface IveFXS { struct LockedBalance { int128 amount; uint256 end; } function commit_transfer_ownership(address addr) external; function apply_transfer_ownership() external; function commit_smart_wallet_checker(address addr) external; function apply_smart_wallet_checker() external; function toggleEmergencyUnlock() external; function recoverERC20(address token_addr, uint256 amount) external; function get_last_user_slope(address addr) external view returns (int128); function user_point_history__ts(address _addr, uint256 _idx) external view returns (uint256); function locked__end(address _addr) external view returns (uint256); function checkpoint() external; function deposit_for(address _addr, uint256 _value) external; function create_lock(uint256 _value, uint256 _unlock_time) external; function increase_amount(uint256 _value) external; function increase_unlock_time(uint256 _unlock_time) external; function withdraw() external; function balanceOf(address addr) external view returns (uint256); function balanceOf(address addr, uint256 _t) external view returns (uint256); function balanceOfAt(address addr, uint256 _block) external view returns (uint256); function totalSupply() external view returns (uint256); function totalSupply(uint256 t) external view returns (uint256); function totalSupplyAt(uint256 _block) external view returns (uint256); function totalFXSSupply() external view returns (uint256); function totalFXSSupplyAt(uint256 _block) external view returns (uint256); function changeController(address _newController) external; function token() external view returns (address); function supply() external view returns (uint256); function locked(address addr) external view returns (LockedBalance memory); function epoch() external view returns (uint256); function point_history(uint256 arg0) external view returns (int128 bias, int128 slope, uint256 ts, uint256 blk, uint256 fxs_amt); function user_point_history(address arg0, uint256 arg1) external view returns (int128 bias, int128 slope, uint256 ts, uint256 blk, uint256 fxs_amt); function user_point_epoch(address arg0) external view returns (uint256); function slope_changes(uint256 arg0) external view returns (int128); function controller() external view returns (address); function transfersEnabled() external view returns (bool); function emergencyUnlockActive() external view returns (bool); function name() external view returns (string memory); function symbol() external view returns (string memory); function version() external view returns (string memory); function decimals() external view returns (uint256); function future_smart_wallet_checker() external view returns (address); function smart_wallet_checker() external view returns (address); function admin() external view returns (address); function future_admin() external view returns (address); } // File contracts/Curve/IFraxGaugeController.sol // https://github.com/swervefi/swerve/edit/master/packages/swerve-contracts/interfaces/IGaugeController.sol interface IFraxGaugeController { struct Point { uint256 bias; uint256 slope; } struct VotedSlope { uint256 slope; uint256 power; uint256 end; } // Public variables function admin() external view returns (address); function future_admin() external view returns (address); function token() external view returns (address); function voting_escrow() external view returns (address); function n_gauge_types() external view returns (int128); function n_gauges() external view returns (int128); function gauge_type_names(int128) external view returns (string memory); function gauges(uint256) external view returns (address); function vote_user_slopes(address, address) external view returns (VotedSlope memory); function vote_user_power(address) external view returns (uint256); function last_user_vote(address, address) external view returns (uint256); function points_weight(address, uint256) external view returns (Point memory); function time_weight(address) external view returns (uint256); function points_sum(int128, uint256) external view returns (Point memory); function time_sum(uint256) external view returns (uint256); function points_total(uint256) external view returns (uint256); function time_total() external view returns (uint256); function points_type_weight(int128, uint256) external view returns (uint256); function time_type_weight(uint256) external view returns (uint256); // Getter functions function gauge_types(address) external view returns (int128); function gauge_relative_weight(address) external view returns (uint256); function gauge_relative_weight(address, uint256) external view returns (uint256); function get_gauge_weight(address) external view returns (uint256); function get_type_weight(int128) external view returns (uint256); function get_total_weight() external view returns (uint256); function get_weights_sum_per_type(int128) external view returns (uint256); // External functions function commit_transfer_ownership(address) external; function apply_transfer_ownership() external; function add_gauge( address, int128, uint256 ) external; function checkpoint() external; function checkpoint_gauge(address) external; function global_emission_rate() external view returns (uint256); function gauge_relative_weight_write(address) external returns (uint256); function gauge_relative_weight_write(address, uint256) external returns (uint256); function add_type(string memory, uint256) external; function change_type_weight(int128, uint256) external; function change_gauge_weight(address, uint256) external; function change_global_emission_rate(uint256) external; function vote_for_gauge_weights(address, uint256) external; } // File contracts/Curve/IFraxGaugeFXSRewardsDistributor.sol interface IFraxGaugeFXSRewardsDistributor { function acceptOwnership() external; function curator_address() external view returns(address); function currentReward(address gauge_address) external view returns(uint256 reward_amount); function distributeReward(address gauge_address) external returns(uint256 weeks_elapsed, uint256 reward_tally); function distributionsOn() external view returns(bool); function gauge_whitelist(address) external view returns(bool); function is_middleman(address) external view returns(bool); function last_time_gauge_paid(address) external view returns(uint256); function nominateNewOwner(address _owner) external; function nominatedOwner() external view returns(address); function owner() external view returns(address); function recoverERC20(address tokenAddress, uint256 tokenAmount) external; function setCurator(address _new_curator_address) external; function setGaugeController(address _gauge_controller_address) external; function setGaugeState(address _gauge_address, bool _is_middleman, bool _is_active) external; function setTimelock(address _new_timelock) external; function timelock_address() external view returns(address); function toggleDistributions() external; } // File contracts/Common/Context.sol /* * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with GSN 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 payable) { return payable(msg.sender); } function _msgData() internal view virtual returns (bytes memory) { this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691 return msg.data; } } // File contracts/Math/SafeMath.sol /** * @dev Wrappers over Solidity's arithmetic operations with added overflow * checks. * * Arithmetic operations in Solidity wrap on overflow. This can easily result * in bugs, because programmers usually assume that an overflow raises an * error, which is the standard behavior in high level programming languages. * `SafeMath` restores this intuition by reverting the transaction when an * operation overflows. * * Using this library instead of the unchecked operations eliminates an entire * class of bugs, so it's recommended to use it always. */ library SafeMath { /** * @dev Returns the addition of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `+` operator. * * Requirements: * - Addition cannot overflow. */ function add(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c = a + b; require(c >= a, "SafeMath: addition overflow"); return c; } /** * @dev Returns the subtraction of two unsigned integers, reverting on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b) internal pure returns (uint256) { return sub(a, b, "SafeMath: subtraction overflow"); } /** * @dev Returns the subtraction of two unsigned integers, reverting with custom message on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * - Subtraction cannot overflow. * * _Available since v2.4.0._ */ function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b <= a, errorMessage); uint256 c = a - b; return c; } /** * @dev Returns the multiplication of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `*` operator. * * Requirements: * - Multiplication cannot overflow. */ function mul(uint256 a, uint256 b) internal pure returns (uint256) { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 if (a == 0) { return 0; } uint256 c = a * b; require(c / a == b, "SafeMath: multiplication overflow"); return c; } /** * @dev Returns the integer division of two unsigned integers. Reverts on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * - The divisor cannot be zero. */ function div(uint256 a, uint256 b) internal pure returns (uint256) { return div(a, b, "SafeMath: division by zero"); } /** * @dev Returns the integer division of two unsigned integers. Reverts with custom message on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * - The divisor cannot be zero. * * _Available since v2.4.0._ */ function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { // Solidity only automatically asserts when dividing by 0 require(b > 0, errorMessage); uint256 c = a / b; // assert(a == b * c + a % b); // There is no case in which this doesn't hold return c; } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * Reverts when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b) internal pure returns (uint256) { return mod(a, b, "SafeMath: modulo by zero"); } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * Reverts with custom message when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * - The divisor cannot be zero. * * _Available since v2.4.0._ */ function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b != 0, errorMessage); return a % b; } } // File contracts/ERC20/IERC20.sol /** * @dev Interface of the ERC20 standard as defined in the EIP. Does not include * the optional functions; to access them see {ERC20Detailed}. */ interface IERC20 { /** * @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 `recipient`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address recipient, 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 `sender` to `recipient` 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 sender, address recipient, uint256 amount) external returns (bool); /** * @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); } // File contracts/Utils/Address.sol /** * @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 * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize, which returns 0 for contracts in // construction, since the code is only stored at the end of the // constructor execution. uint256 size; // solhint-disable-next-line no-inline-assembly assembly { size := extcodesize(account) } return size > 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"); // solhint-disable-next-line avoid-low-level-calls, avoid-call-value (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"); // solhint-disable-next-line avoid-low-level-calls (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"); // solhint-disable-next-line avoid-low-level-calls (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"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = target.delegatecall(data); return _verifyCallResult(success, returndata, errorMessage); } function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private 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 // solhint-disable-next-line no-inline-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } } } // File contracts/ERC20/ERC20.sol /** * @dev Implementation of the {IERC20} interface. * * This implementation is agnostic to the way tokens are created. This means * that a supply mechanism has to be added in a derived contract using {_mint}. * For a generic mechanism see {ERC20Mintable}. * * TIP: For a detailed writeup see our guide * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How * to implement supply mechanisms]. * * We have followed general OpenZeppelin guidelines: functions revert instead * of returning `false` on failure. This behavior is nonetheless conventional * and does not conflict with the expectations of ERC20 applications. * * Additionally, an {Approval} event is emitted on calls to {transferFrom}. * This allows applications to reconstruct the allowance for all accounts just * by listening to said events. Other implementations of the EIP may not emit * these events, as it isn't required by the specification. * * Finally, the non-standard {decreaseAllowance} and {increaseAllowance} * functions have been added to mitigate the well-known issues around setting * allowances. See {IERC20-approve}. */ contract ERC20 is Context, IERC20 { using SafeMath for uint256; mapping (address => uint256) private _balances; mapping (address => mapping (address => uint256)) private _allowances; uint256 private _totalSupply; string private _name; string private _symbol; uint8 private _decimals; /** * @dev Sets the values for {name} and {symbol}, initializes {decimals} with * a default value of 18. * * To select a different value for {decimals}, use {_setupDecimals}. * * All three of these values are immutable: they can only be set once during * construction. */ constructor (string memory __name, string memory __symbol) public { _name = __name; _symbol = __symbol; _decimals = 18; } /** * @dev Returns the name of the token. */ function name() public view returns (string memory) { return _name; } /** * @dev Returns the symbol of the token, usually a shorter version of the * name. */ function symbol() public view returns (string memory) { return _symbol; } /** * @dev Returns the number of decimals used to get its user representation. * For example, if `decimals` equals `2`, a balance of `505` tokens should * be displayed to a user as `5,05` (`505 / 10 ** 2`). * * Tokens usually opt for a value of 18, imitating the relationship between * Ether and Wei. This is the value {ERC20} uses, unless {_setupDecimals} is * called. * * NOTE: This information is only used for _display_ purposes: it in * no way affects any of the arithmetic of the contract, including * {IERC20-balanceOf} and {IERC20-transfer}. */ function decimals() public view returns (uint8) { return _decimals; } /** * @dev See {IERC20-totalSupply}. */ function totalSupply() public view override returns (uint256) { return _totalSupply; } /** * @dev See {IERC20-balanceOf}. */ function balanceOf(address account) public view override returns (uint256) { return _balances[account]; } /** * @dev See {IERC20-transfer}. * * Requirements: * * - `recipient` cannot be the zero address. * - the caller must have a balance of at least `amount`. */ function transfer(address recipient, uint256 amount) public virtual override returns (bool) { _transfer(_msgSender(), recipient, amount); return true; } /** * @dev See {IERC20-allowance}. */ function allowance(address owner, address spender) public view virtual override returns (uint256) { return _allowances[owner][spender]; } /** * @dev See {IERC20-approve}. * * Requirements: * * - `spender` cannot be the zero address.approve(address spender, uint256 amount) */ function approve(address spender, uint256 amount) public virtual override returns (bool) { _approve(_msgSender(), spender, amount); return true; } /** * @dev See {IERC20-transferFrom}. * * Emits an {Approval} event indicating the updated allowance. This is not * required by the EIP. See the note at the beginning of {ERC20}; * * Requirements: * - `sender` and `recipient` cannot be the zero address. * - `sender` must have a balance of at least `amount`. * - the caller must have allowance for `sender`'s tokens of at least * `amount`. */ function transferFrom(address sender, address recipient, uint256 amount) public virtual override returns (bool) { _transfer(sender, recipient, amount); _approve(sender, _msgSender(), _allowances[sender][_msgSender()].sub(amount, "ERC20: transfer amount exceeds allowance")); return true; } /** * @dev Atomically increases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. */ function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) { _approve(_msgSender(), spender, _allowances[_msgSender()][spender].add(addedValue)); return true; } /** * @dev Atomically decreases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. * - `spender` must have allowance for the caller of at least * `subtractedValue`. */ function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) { _approve(_msgSender(), spender, _allowances[_msgSender()][spender].sub(subtractedValue, "ERC20: decreased allowance below zero")); return true; } /** * @dev Moves tokens `amount` from `sender` to `recipient`. * * This is internal function is equivalent to {transfer}, and can be used to * e.g. implement automatic token fees, slashing mechanisms, etc. * * Emits a {Transfer} event. * * Requirements: * * - `sender` cannot be the zero address. * - `recipient` cannot be the zero address. * - `sender` must have a balance of at least `amount`. */ function _transfer(address sender, address recipient, uint256 amount) internal virtual { require(sender != address(0), "ERC20: transfer from the zero address"); require(recipient != address(0), "ERC20: transfer to the zero address"); _beforeTokenTransfer(sender, recipient, amount); _balances[sender] = _balances[sender].sub(amount, "ERC20: transfer amount exceeds balance"); _balances[recipient] = _balances[recipient].add(amount); emit Transfer(sender, recipient, amount); } /** @dev Creates `amount` tokens and assigns them to `account`, increasing * the total supply. * * Emits a {Transfer} event with `from` set to the zero address. * * Requirements * * - `to` cannot be the zero address. */ function _mint(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: mint to the zero address"); _beforeTokenTransfer(address(0), account, amount); _totalSupply = _totalSupply.add(amount); _balances[account] = _balances[account].add(amount); emit Transfer(address(0), account, amount); } /** * @dev Destroys `amount` tokens from the caller. * * See {ERC20-_burn}. */ function burn(uint256 amount) public virtual { _burn(_msgSender(), amount); } /** * @dev Destroys `amount` tokens from `account`, deducting from the caller's * allowance. * * See {ERC20-_burn} and {ERC20-allowance}. * * Requirements: * * - the caller must have allowance for `accounts`'s tokens of at least * `amount`. */ function burnFrom(address account, uint256 amount) public virtual { uint256 decreasedAllowance = allowance(account, _msgSender()).sub(amount, "ERC20: burn amount exceeds allowance"); _approve(account, _msgSender(), decreasedAllowance); _burn(account, amount); } /** * @dev Destroys `amount` tokens from `account`, reducing the * total supply. * * Emits a {Transfer} event with `to` set to the zero address. * * Requirements * * - `account` cannot be the zero address. * - `account` must have at least `amount` tokens. */ function _burn(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: burn from the zero address"); _beforeTokenTransfer(account, address(0), amount); _balances[account] = _balances[account].sub(amount, "ERC20: burn amount exceeds balance"); _totalSupply = _totalSupply.sub(amount); emit Transfer(account, address(0), amount); } /** * @dev Sets `amount` as the allowance of `spender` over the `owner`s tokens. * * This is internal function is equivalent to `approve`, and can be used to * e.g. set automatic allowances for certain subsystems, etc. * * Emits an {Approval} event. * * Requirements: * * - `owner` cannot be the zero address. * - `spender` cannot be the zero address. */ function _approve(address owner, address spender, uint256 amount) internal virtual { require(owner != address(0), "ERC20: approve from the zero address"); require(spender != address(0), "ERC20: approve to the zero address"); _allowances[owner][spender] = amount; emit Approval(owner, spender, amount); } /** * @dev Destroys `amount` tokens from `account`.`amount` is then deducted * from the caller's allowance. * * See {_burn} and {_approve}. */ function _burnFrom(address account, uint256 amount) internal virtual { _burn(account, amount); _approve(account, _msgSender(), _allowances[account][_msgSender()].sub(amount, "ERC20: burn amount exceeds allowance")); } /** * @dev Hook that is called before any transfer of tokens. This includes * minting and burning. * * Calling conditions: * * - when `from` and `to` are both non-zero, `amount` of `from`'s tokens * will be to transferred to `to`. * - when `from` is zero, `amount` tokens will be minted for `to`. * - when `to` is zero, `amount` of `from`'s tokens will be burned. * - `from` and `to` are never both zero. * * To learn more about hooks, head to xref:ROOT:using-hooks.adoc[Using Hooks]. */ function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual { } } // File contracts/Uniswap/TransferHelper.sol // helper methods for interacting with ERC20 tokens and sending ETH that do not consistently return true/false library TransferHelper { function safeApprove(address token, address to, uint value) internal { // bytes4(keccak256(bytes('approve(address,uint256)'))); (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x095ea7b3, to, value)); require(success && (data.length == 0 || abi.decode(data, (bool))), 'TransferHelper: APPROVE_FAILED'); } function safeTransfer(address token, address to, uint value) internal { // bytes4(keccak256(bytes('transfer(address,uint256)'))); (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0xa9059cbb, to, value)); require(success && (data.length == 0 || abi.decode(data, (bool))), 'TransferHelper: TRANSFER_FAILED'); } function safeTransferFrom(address token, address from, address to, uint value) internal { // bytes4(keccak256(bytes('transferFrom(address,address,uint256)'))); (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x23b872dd, from, to, value)); require(success && (data.length == 0 || abi.decode(data, (bool))), 'TransferHelper: TRANSFER_FROM_FAILED'); } function safeTransferETH(address to, uint value) internal { (bool success,) = to.call{value:value}(new bytes(0)); require(success, 'TransferHelper: ETH_TRANSFER_FAILED'); } } // File contracts/ERC20/SafeERC20.sol /** * @title SafeERC20 * @dev Wrappers around ERC20 operations that throw on failure (when the token * contract returns false). Tokens that return no value (and instead revert or * throw on failure) are also supported, non-reverting calls are assumed to be * successful. * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. */ library SafeERC20 { using SafeMath for uint256; 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' // solhint-disable-next-line max-line-length 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).add(value); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal { uint256 newAllowance = token.allowance(address(this), spender).sub(value, "SafeERC20: decreased allowance below zero"); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } /** * @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 // solhint-disable-next-line max-line-length require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); } } } // File contracts/Utils/ReentrancyGuard.sol /** * @dev Contract module that helps prevent reentrant calls to a function. * * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier * available, which can be applied to functions to make sure there are no nested * (reentrant) calls to them. * * Note that because there is a single `nonReentrant` guard, functions marked as * `nonReentrant` may not call one another. This can be worked around by making * those functions `private`, and then adding `external` `nonReentrant` entry * points to them. * * TIP: If 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 () internal { _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 make 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 contracts/Staking/Owned.sol // https://docs.synthetix.io/contracts/Owned contract Owned { address public owner; address public nominatedOwner; constructor (address _owner) public { require(_owner != address(0), "Owner address cannot be 0"); owner = _owner; emit OwnerChanged(address(0), _owner); } function nominateNewOwner(address _owner) external onlyOwner { nominatedOwner = _owner; emit OwnerNominated(_owner); } function acceptOwnership() external { require(msg.sender == nominatedOwner, "You must be nominated before you can accept ownership"); emit OwnerChanged(owner, nominatedOwner); owner = nominatedOwner; nominatedOwner = address(0); } modifier onlyOwner { require(msg.sender == owner, "Only the contract owner may perform this action"); _; } event OwnerNominated(address newOwner); event OwnerChanged(address oldOwner, address newOwner); } // File contracts/Staking/FraxUnifiedFarmTemplate.sol pragma experimental ABIEncoderV2; // ==================================================================== // | ______ _______ | // | / _____________ __ __ / ____(_____ ____ _____ ________ | // | / /_ / ___/ __ `| |/_/ / /_ / / __ \/ __ `/ __ \/ ___/ _ \ | // | / __/ / / / /_/ _> < / __/ / / / / / /_/ / / / / /__/ __/ | // | /_/ /_/ \__,_/_/|_| /_/ /_/_/ /_/\__,_/_/ /_/\___/\___/ | // | | // ==================================================================== // ====================== FraxUnifiedFarmTemplate ===================== // ==================================================================== // Migratable Farming contract that accounts for veFXS // Overrideable for UniV3, ERC20s, etc // New for V2 // - Multiple reward tokens possible // - Can add to existing locked stakes // - Contract is aware of proxied veFXS // - veFXS multiplier formula changed // Apes together strong // Frax Finance: https://github.com/FraxFinance // Primary Author(s) // Travis Moore: https://github.com/FortisFortuna // Reviewer(s) / Contributor(s) // Jason Huan: https://github.com/jasonhuan // Sam Kazemian: https://github.com/samkazemian // Dennis: github.com/denett // Sam Sun: https://github.com/samczsun // Originally inspired by Synthetix.io, but heavily modified by the Frax team // (Locked, veFXS, and UniV3 portions are new) // https://raw.githubusercontent.com/Synthetixio/synthetix/develop/contracts/StakingRewards.sol contract FraxUnifiedFarmTemplate is Owned, ReentrancyGuard { using SafeERC20 for ERC20; /* ========== STATE VARIABLES ========== */ // Instances IveFXS private veFXS = IveFXS(0xc8418aF6358FFddA74e09Ca9CC3Fe03Ca6aDC5b0); // Frax related address internal constant frax_address = 0x853d955aCEf822Db058eb8505911ED77F175b99e; bool internal frax_is_token0; uint256 private fraxPerLPStored; // Constant for various precisions uint256 internal constant MULTIPLIER_PRECISION = 1e18; // Time tracking uint256 public periodFinish; uint256 public lastUpdateTime; // Lock time and multiplier settings uint256 public lock_max_multiplier = uint256(3e18); // E18. 1x = e18 uint256 public lock_time_for_max_multiplier = 3 * 365 * 86400; // 3 years uint256 public lock_time_min = 86400; // 1 * 86400 (1 day) // veFXS related uint256 public vefxs_boost_scale_factor = uint256(4e18); // E18. 4x = 4e18; 100 / scale_factor = % vefxs supply needed for max boost uint256 public vefxs_max_multiplier = uint256(2e18); // E18. 1x = 1e18 uint256 public vefxs_per_frax_for_max_boost = uint256(2e18); // E18. 2e18 means 2 veFXS must be held by the staker per 1 FRAX mapping(address => uint256) internal _vefxsMultiplierStored; mapping(address => bool) internal valid_vefxs_proxies; mapping(address => mapping(address => bool)) internal proxy_allowed_stakers; // Reward addresses, gauge addresses, reward rates, and reward managers mapping(address => address) public rewardManagers; // token addr -> manager addr address[] internal rewardTokens; address[] internal gaugeControllers; address[] internal rewardDistributors; uint256[] internal rewardRatesManual; mapping(address => uint256) public rewardTokenAddrToIdx; // token addr -> token index // Reward period uint256 public constant rewardsDuration = 604800; // 7 * 86400 (7 days) // Reward tracking uint256[] private rewardsPerTokenStored; mapping(address => mapping(uint256 => uint256)) private userRewardsPerTokenPaid; // staker addr -> token id -> paid amount mapping(address => mapping(uint256 => uint256)) private rewards; // staker addr -> token id -> reward amount mapping(address => uint256) internal lastRewardClaimTime; // staker addr -> timestamp // Gauge tracking uint256[] private last_gauge_relative_weights; uint256[] private last_gauge_time_totals; // Balance tracking uint256 internal _total_liquidity_locked; uint256 internal _total_combined_weight; mapping(address => uint256) internal _locked_liquidity; mapping(address => uint256) internal _combined_weights; mapping(address => uint256) public proxy_lp_balances; // Keeps track of LP balances proxy-wide. Needed to make sure the proxy boost is kept in line // List of valid migrators (set by governance) mapping(address => bool) internal valid_migrators; // Stakers set which migrator(s) they want to use mapping(address => mapping(address => bool)) internal staker_allowed_migrators; mapping(address => address) public staker_designated_proxies; // Keep public so users can see on the frontend if they have a proxy // Admin booleans for emergencies, migrations, and overrides bool public stakesUnlocked; // Release locked stakes in case of emergency bool internal migrationsOn; // Used for migrations. Prevents new stakes, but allows LP and reward withdrawals bool internal withdrawalsPaused; // For emergencies bool internal rewardsCollectionPaused; // For emergencies bool internal stakingPaused; // For emergencies /* ========== STRUCTS ========== */ // In children... /* ========== MODIFIERS ========== */ modifier onlyByOwnGov() { require(msg.sender == owner || msg.sender == 0x8412ebf45bAC1B340BbE8F318b928C466c4E39CA, "Not owner or timelock"); _; } modifier onlyTknMgrs(address reward_token_address) { require(msg.sender == owner || isTokenManagerFor(msg.sender, reward_token_address), "Not owner or tkn mgr"); _; } modifier isMigrating() { require(migrationsOn == true, "Not in migration"); _; } modifier updateRewardAndBalance(address account, bool sync_too) { _updateRewardAndBalance(account, sync_too); _; } /* ========== CONSTRUCTOR ========== */ constructor ( address _owner, address[] memory _rewardTokens, address[] memory _rewardManagers, uint256[] memory _rewardRatesManual, address[] memory _gaugeControllers, address[] memory _rewardDistributors ) Owned(_owner) { // Address arrays rewardTokens = _rewardTokens; gaugeControllers = _gaugeControllers; rewardDistributors = _rewardDistributors; rewardRatesManual = _rewardRatesManual; for (uint256 i = 0; i < _rewardTokens.length; i++){ // For fast token address -> token ID lookups later rewardTokenAddrToIdx[_rewardTokens[i]] = i; // Initialize the stored rewards rewardsPerTokenStored.push(0); // Initialize the reward managers rewardManagers[_rewardTokens[i]] = _rewardManagers[i]; // Push in empty relative weights to initialize the array last_gauge_relative_weights.push(0); // Push in empty time totals to initialize the array last_gauge_time_totals.push(0); } // Other booleans stakesUnlocked = false; // Initialization lastUpdateTime = block.timestamp; periodFinish = block.timestamp + rewardsDuration; } /* ============= VIEWS ============= */ // ------ REWARD RELATED ------ // See if the caller_addr is a manager for the reward token function isTokenManagerFor(address caller_addr, address reward_token_addr) public view returns (bool){ if (caller_addr == owner) return true; // Contract owner else if (rewardManagers[reward_token_addr] == caller_addr) return true; // Reward manager return false; } // All the reward tokens function getAllRewardTokens() external view returns (address[] memory) { return rewardTokens; } // Last time the reward was applicable function lastTimeRewardApplicable() internal view returns (uint256) { return Math.min(block.timestamp, periodFinish); } function rewardRates(uint256 token_idx) public view returns (uint256 rwd_rate) { address gauge_controller_address = gaugeControllers[token_idx]; if (gauge_controller_address != address(0)) { rwd_rate = (IFraxGaugeController(gauge_controller_address).global_emission_rate() * last_gauge_relative_weights[token_idx]) / 1e18; } else { rwd_rate = rewardRatesManual[token_idx]; } } // Amount of reward tokens per LP token / liquidity unit function rewardsPerToken() public view returns (uint256[] memory newRewardsPerTokenStored) { if (_total_liquidity_locked == 0 || _total_combined_weight == 0) { return rewardsPerTokenStored; } else { newRewardsPerTokenStored = new uint256[](rewardTokens.length); for (uint256 i = 0; i < rewardsPerTokenStored.length; i++){ newRewardsPerTokenStored[i] = rewardsPerTokenStored[i] + ( ((lastTimeRewardApplicable() - lastUpdateTime) * rewardRates(i) * 1e18) / _total_combined_weight ); } return newRewardsPerTokenStored; } } // Amount of reward tokens an account has earned / accrued // Note: In the edge-case of one of the account's stake expiring since the last claim, this will // return a slightly inflated number function earned(address account) public view returns (uint256[] memory new_earned) { uint256[] memory reward_arr = rewardsPerToken(); new_earned = new uint256[](rewardTokens.length); if (_combined_weights[account] > 0){ for (uint256 i = 0; i < rewardTokens.length; i++){ new_earned[i] = ((_combined_weights[account] * (reward_arr[i] - userRewardsPerTokenPaid[account][i])) / 1e18) + rewards[account][i]; } } } // Total reward tokens emitted in the given period function getRewardForDuration() external view returns (uint256[] memory rewards_per_duration_arr) { rewards_per_duration_arr = new uint256[](rewardRatesManual.length); for (uint256 i = 0; i < rewardRatesManual.length; i++){ rewards_per_duration_arr[i] = rewardRates(i) * rewardsDuration; } } // ------ LIQUIDITY AND WEIGHTS ------ // User locked liquidity / LP tokens function totalLiquidityLocked() external view returns (uint256) { return _total_liquidity_locked; } // Total locked liquidity / LP tokens function lockedLiquidityOf(address account) external view returns (uint256) { return _locked_liquidity[account]; } // Total combined weight function totalCombinedWeight() external view returns (uint256) { return _total_combined_weight; } // Total 'balance' used for calculating the percent of the pool the account owns // Takes into account the locked stake time multiplier and veFXS multiplier function combinedWeightOf(address account) external view returns (uint256) { return _combined_weights[account]; } // Calculated the combined weight for an account function calcCurCombinedWeight(address account) public virtual view returns ( uint256 old_combined_weight, uint256 new_vefxs_multiplier, uint256 new_combined_weight ) { revert("Need cCCW logic"); } // ------ LOCK RELATED ------ // Multiplier amount, given the length of the lock function lockMultiplier(uint256 secs) public view returns (uint256) { return Math.min( lock_max_multiplier, uint256(MULTIPLIER_PRECISION) + ( (secs * (lock_max_multiplier - MULTIPLIER_PRECISION)) / lock_time_for_max_multiplier ) ) ; } // ------ FRAX RELATED ------ function userStakedFrax(address account) public view returns (uint256) { return (fraxPerLPStored * _locked_liquidity[account]) / MULTIPLIER_PRECISION; } function proxyStakedFrax(address proxy_address) public view returns (uint256) { return (fraxPerLPStored * proxy_lp_balances[proxy_address]) / MULTIPLIER_PRECISION; } // Max LP that can get max veFXS boosted for a given address at its current veFXS balance function maxLPForMaxBoost(address account) external view returns (uint256) { return (veFXS.balanceOf(account) * MULTIPLIER_PRECISION * MULTIPLIER_PRECISION) / (vefxs_per_frax_for_max_boost * fraxPerLPStored); } // Meant to be overridden function fraxPerLPToken() public virtual view returns (uint256) { revert("Need fPLPT logic"); } // ------ veFXS RELATED ------ function minVeFXSForMaxBoost(address account) public view returns (uint256) { return (userStakedFrax(account) * vefxs_per_frax_for_max_boost) / MULTIPLIER_PRECISION; } function minVeFXSForMaxBoostProxy(address proxy_address) public view returns (uint256) { return (proxyStakedFrax(proxy_address) * vefxs_per_frax_for_max_boost) / MULTIPLIER_PRECISION; } function veFXSMultiplier(address account) public view returns (uint256 vefxs_multiplier) { // Use either the user's or their proxy's veFXS balance uint256 vefxs_bal_to_use = 0; address the_proxy = staker_designated_proxies[account]; vefxs_bal_to_use = (the_proxy == address(0)) ? veFXS.balanceOf(account) : veFXS.balanceOf(the_proxy); // First option based on fraction of total veFXS supply, with an added scale factor uint256 mult_optn_1 = (vefxs_bal_to_use * vefxs_max_multiplier * vefxs_boost_scale_factor) / (veFXS.totalSupply() * MULTIPLIER_PRECISION); // Second based on old method, where the amount of FRAX staked comes into play uint256 mult_optn_2; { uint256 veFXS_needed_for_max_boost; // Need to use proxy-wide FRAX balance if applicable, to prevent exploiting veFXS_needed_for_max_boost = (the_proxy == address(0)) ? minVeFXSForMaxBoost(account) : minVeFXSForMaxBoostProxy(the_proxy); if (veFXS_needed_for_max_boost > 0){ uint256 user_vefxs_fraction = (vefxs_bal_to_use * MULTIPLIER_PRECISION) / veFXS_needed_for_max_boost; mult_optn_2 = (user_vefxs_fraction * vefxs_max_multiplier) / MULTIPLIER_PRECISION; } else mult_optn_2 = 0; // This will happen with the first stake, when user_staked_frax is 0 } // Select the higher of the two vefxs_multiplier = (mult_optn_1 > mult_optn_2 ? mult_optn_1 : mult_optn_2); // Cap the boost to the vefxs_max_multiplier if (vefxs_multiplier > vefxs_max_multiplier) vefxs_multiplier = vefxs_max_multiplier; } /* =============== MUTATIVE FUNCTIONS =============== */ // ------ MIGRATIONS ------ // Staker can allow a migrator function stakerToggleMigrator(address migrator_address) external { require(valid_migrators[migrator_address], "Invalid migrator address"); staker_allowed_migrators[msg.sender][migrator_address] = !staker_allowed_migrators[msg.sender][migrator_address]; } // Proxy can allow a staker to use their veFXS balance (the staker will have to reciprocally toggle them too) // Must come before stakerSetVeFXSProxy function proxyToggleStaker(address staker_address) external { require(valid_vefxs_proxies[msg.sender], "Invalid proxy"); proxy_allowed_stakers[msg.sender][staker_address] = !proxy_allowed_stakers[msg.sender][staker_address]; // Disable the staker's set proxy if it was the toggler and is currently on if (staker_designated_proxies[staker_address] == msg.sender){ staker_designated_proxies[staker_address] = address(0); // Remove the LP as well proxy_lp_balances[msg.sender] -= _locked_liquidity[staker_address]; } } // Staker can allow a veFXS proxy (the proxy will have to toggle them first) function stakerSetVeFXSProxy(address proxy_address) external { require(valid_vefxs_proxies[proxy_address], "Invalid proxy"); require(proxy_allowed_stakers[proxy_address][msg.sender], "Proxy has not allowed you yet"); staker_designated_proxies[msg.sender] = proxy_address; // Add the the LP as well proxy_lp_balances[proxy_address] += _locked_liquidity[msg.sender]; } // ------ STAKING ------ // In children... // ------ WITHDRAWING ------ // In children... // ------ REWARDS SYNCING ------ function _updateRewardAndBalance(address account, bool sync_too) internal { // Need to retro-adjust some things if the period hasn't been renewed, then start a new one if (sync_too){ sync(); } if (account != address(0)) { // To keep the math correct, the user's combined weight must be recomputed to account for their // ever-changing veFXS balance. ( uint256 old_combined_weight, uint256 new_vefxs_multiplier, uint256 new_combined_weight ) = calcCurCombinedWeight(account); // Calculate the earnings first _syncEarned(account); // Update the user's stored veFXS multipliers _vefxsMultiplierStored[account] = new_vefxs_multiplier; // Update the user's and the global combined weights if (new_combined_weight >= old_combined_weight) { uint256 weight_diff = new_combined_weight - old_combined_weight; _total_combined_weight = _total_combined_weight + weight_diff; _combined_weights[account] = old_combined_weight + weight_diff; } else { uint256 weight_diff = old_combined_weight - new_combined_weight; _total_combined_weight = _total_combined_weight - weight_diff; _combined_weights[account] = old_combined_weight - weight_diff; } } } function _syncEarned(address account) internal { if (account != address(0)) { // Calculate the earnings uint256[] memory earned_arr = earned(account); // Update the rewards array for (uint256 i = 0; i < earned_arr.length; i++){ rewards[account][i] = earned_arr[i]; } // Update the rewards paid array for (uint256 i = 0; i < earned_arr.length; i++){ userRewardsPerTokenPaid[account][i] = rewardsPerTokenStored[i]; } } } // ------ REWARDS CLAIMING ------ function _getRewardExtraLogic(address rewardee, address destination_address) internal virtual { revert("Need gREL logic"); } // Two different getReward functions are needed because of delegateCall and msg.sender issues function getReward(address destination_address) external nonReentrant returns (uint256[] memory) { require(rewardsCollectionPaused == false, "Rewards collection paused"); return _getReward(msg.sender, destination_address); } // No withdrawer == msg.sender check needed since this is only internally callable function _getReward(address rewardee, address destination_address) internal updateRewardAndBalance(rewardee, true) returns (uint256[] memory rewards_before) { // Update the rewards array and distribute rewards rewards_before = new uint256[](rewardTokens.length); for (uint256 i = 0; i < rewardTokens.length; i++){ rewards_before[i] = rewards[rewardee][i]; rewards[rewardee][i] = 0; TransferHelper.safeTransfer(rewardTokens[i], destination_address, rewards_before[i]); } // Handle additional reward logic _getRewardExtraLogic(rewardee, destination_address); // Update the last reward claim time lastRewardClaimTime[rewardee] = block.timestamp; } // ------ FARM SYNCING ------ // If the period expired, renew it function retroCatchUp() internal { // Pull in rewards from the rewards distributor, if applicable for (uint256 i = 0; i < rewardDistributors.length; i++){ address reward_distributor_address = rewardDistributors[i]; if (reward_distributor_address != address(0)) { IFraxGaugeFXSRewardsDistributor(reward_distributor_address).distributeReward(address(this)); } } // Ensure the provided reward amount is not more than the balance in the contract. // This keeps the reward rate in the right range, preventing overflows due to // very high values of rewardRate in the earned and rewardsPerToken functions; // Reward + leftover must be less than 2^256 / 10^18 to avoid overflow. uint256 num_periods_elapsed = uint256(block.timestamp - periodFinish) / rewardsDuration; // Floor division to the nearest period // Make sure there are enough tokens to renew the reward period for (uint256 i = 0; i < rewardTokens.length; i++){ require((rewardRates(i) * rewardsDuration * (num_periods_elapsed + 1)) <= ERC20(rewardTokens[i]).balanceOf(address(this)), string(abi.encodePacked("Not enough reward tokens available: ", rewardTokens[i])) ); } // uint256 old_lastUpdateTime = lastUpdateTime; // uint256 new_lastUpdateTime = block.timestamp; // lastUpdateTime = periodFinish; periodFinish = periodFinish + ((num_periods_elapsed + 1) * rewardsDuration); // Update the rewards and time _updateStoredRewardsAndTime(); // Update the fraxPerLPStored fraxPerLPStored = fraxPerLPToken(); } function _updateStoredRewardsAndTime() internal { // Get the rewards uint256[] memory rewards_per_token = rewardsPerToken(); // Update the rewardsPerTokenStored for (uint256 i = 0; i < rewardsPerTokenStored.length; i++){ rewardsPerTokenStored[i] = rewards_per_token[i]; } // Update the last stored time lastUpdateTime = lastTimeRewardApplicable(); } function sync_gauge_weights(bool force_update) public { // Loop through the gauge controllers for (uint256 i = 0; i < gaugeControllers.length; i++){ address gauge_controller_address = gaugeControllers[i]; if (gauge_controller_address != address(0)) { if (force_update || (block.timestamp > last_gauge_time_totals[i])){ // Update the gauge_relative_weight last_gauge_relative_weights[i] = IFraxGaugeController(gauge_controller_address).gauge_relative_weight_write(address(this), block.timestamp); last_gauge_time_totals[i] = IFraxGaugeController(gauge_controller_address).time_total(); } } } } function sync() public { // Sync the gauge weight, if applicable sync_gauge_weights(false); if (block.timestamp >= periodFinish) { retroCatchUp(); } else { _updateStoredRewardsAndTime(); } } /* ========== RESTRICTED FUNCTIONS - Curator / migrator callable ========== */ // ------ FARM SYNCING ------ // In children... // ------ PAUSES ------ function setPauses( bool _stakingPaused, bool _withdrawalsPaused, bool _rewardsCollectionPaused ) external onlyByOwnGov { stakingPaused = _stakingPaused; withdrawalsPaused = _withdrawalsPaused; rewardsCollectionPaused = _rewardsCollectionPaused; } /* ========== RESTRICTED FUNCTIONS - Owner or timelock only ========== */ function unlockStakes() external onlyByOwnGov { stakesUnlocked = !stakesUnlocked; } function toggleMigrations() external onlyByOwnGov { migrationsOn = !migrationsOn; } // Adds supported migrator address function toggleMigrator(address migrator_address) external onlyByOwnGov { valid_migrators[migrator_address] = !valid_migrators[migrator_address]; } // Adds a valid veFXS proxy address function toggleValidVeFXSProxy(address _proxy_addr) external onlyByOwnGov { valid_vefxs_proxies[_proxy_addr] = !valid_vefxs_proxies[_proxy_addr]; } // Added to support recovering LP Rewards and other mistaken tokens from other systems to be distributed to holders function recoverERC20(address tokenAddress, uint256 tokenAmount) external onlyTknMgrs(tokenAddress) { // Check if the desired token is a reward token bool isRewardToken = false; for (uint256 i = 0; i < rewardTokens.length; i++){ if (rewardTokens[i] == tokenAddress) { isRewardToken = true; break; } } // Only the reward managers can take back their reward tokens // Also, other tokens, like the staking token, airdrops, or accidental deposits, can be withdrawn by the owner if ( (isRewardToken && rewardManagers[tokenAddress] == msg.sender) || (!isRewardToken && (msg.sender == owner)) ) { TransferHelper.safeTransfer(tokenAddress, msg.sender, tokenAmount); return; } // If none of the above conditions are true else { revert("No valid tokens to recover"); } } function setMiscVariables( uint256[6] memory _misc_vars // [0]: uint256 _lock_max_multiplier, // [1] uint256 _vefxs_max_multiplier, // [2] uint256 _vefxs_per_frax_for_max_boost, // [3] uint256 _vefxs_boost_scale_factor, // [4] uint256 _lock_time_for_max_multiplier, // [5] uint256 _lock_time_min ) external onlyByOwnGov { require(_misc_vars[0] >= MULTIPLIER_PRECISION, "Must be >= MUL PREC"); require((_misc_vars[1] >= 0) && (_misc_vars[2] >= 0) && (_misc_vars[3] >= 0), "Must be >= 0"); require((_misc_vars[4] >= 1) && (_misc_vars[5] >= 1), "Must be >= 1"); lock_max_multiplier = _misc_vars[0]; vefxs_max_multiplier = _misc_vars[1]; vefxs_per_frax_for_max_boost = _misc_vars[2]; vefxs_boost_scale_factor = _misc_vars[3]; lock_time_for_max_multiplier = _misc_vars[4]; lock_time_min = _misc_vars[5]; } // The owner or the reward token managers can set reward rates function setRewardVars(address reward_token_address, uint256 _new_rate, address _gauge_controller_address, address _rewards_distributor_address) external onlyTknMgrs(reward_token_address) { rewardRatesManual[rewardTokenAddrToIdx[reward_token_address]] = _new_rate; gaugeControllers[rewardTokenAddrToIdx[reward_token_address]] = _gauge_controller_address; rewardDistributors[rewardTokenAddrToIdx[reward_token_address]] = _rewards_distributor_address; } // The owner or the reward token managers can change managers function changeTokenManager(address reward_token_address, address new_manager_address) external onlyTknMgrs(reward_token_address) { rewardManagers[reward_token_address] = new_manager_address; } /* ========== A CHICKEN ========== */ // // ,~. // ,-'__ `-, // {,-' `. } ,') // ,( a ) `-.__ ,',')~, // <=.) ( `-.__,==' ' ' '} // ( ) /) // `-'\ , ) // | \ `~. / // \ `._ \ / // \ `._____,' ,' // `-. ,' // `-._ _,-' // 77jj' // //_|| // __//--'/` // ,--'/` ' // // [hjw] https://textart.io/art/vw6Sa3iwqIRGkZsN1BC2vweF/chicken } // File contracts/Misc_AMOs/vesper/IVPool.sol interface IVPool { function DOMAIN_SEPARATOR() external view returns (bytes32); function MAX_BPS() external view returns (uint256); function VERSION() external view returns (string memory); function acceptGovernorship() external; function addInList(address _listToUpdate, address _addressToAdd) external; function allowance(address owner, address spender) external view returns (uint256); function approve(address spender, uint256 amount) external returns (bool); function availableCreditLimit(address _strategy) external view returns (uint256); function balanceOf(address account) external view returns (uint256); function convertFrom18(uint256 _amount) external view returns (uint256); function decimalConversionFactor() external view returns (uint256); function decimals() external view returns (uint8); function decreaseAllowance(address spender, uint256 subtractedValue) external returns (bool); function deposit(uint256 _amount) external; function depositWithPermit(uint256 _amount, uint256 _deadline, uint8 _v, bytes32 _r, bytes32 _s) external; function excessDebt(address _strategy) external view returns (uint256); function feeCollector() external view returns (address); function feeWhitelist() external view returns (address); function getStrategies() external view returns (address[] memory); function getWithdrawQueue() external view returns (address[] memory); function governor() external view returns (address); function increaseAllowance(address spender, uint256 addedValue) external returns (bool); function initialize(string memory _name, string memory _symbol, address _token, address _poolAccountant, address _addressListFactory) external; function keepers() external view returns (address); function maintainers() external view returns (address); function migrateStrategy(address _old, address _new) external; function multiTransfer(address[] memory _recipients, uint256[] memory _amounts) external returns (bool); function name() external view returns (string memory); function nonces(address) external view returns (uint256); function open() external; function pause() external; function paused() external view returns (bool); function permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) external; function poolAccountant() external view returns (address); function poolRewards() external view returns (address); function pricePerShare() external view returns (uint256); function removeFromList(address _listToUpdate, address _addressToRemove) external; function reportEarning(uint256 _profit, uint256 _loss, uint256 _payback) external; function reportLoss(uint256 _loss) external; function shutdown() external; function stopEverything() external view returns (bool); function strategy(address _strategy) external view returns (bool _active, uint256 _interestFee, uint256 _debtRate, uint256 _lastRebalance, uint256 _totalDebt, uint256 _totalLoss, uint256 _totalProfit, uint256 _debtRatio); function sweepERC20(address _fromToken) external; function symbol() external view returns (string memory); function token() external view returns (address); function tokensHere() external view returns (uint256); function totalDebt() external view returns (uint256); function totalDebtOf(address _strategy) external view returns (uint256); function totalDebtRatio() external view returns (uint256); function totalSupply() external view returns (uint256); function totalValue() external view returns (uint256); function transfer(address recipient, uint256 amount) external returns (bool); function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); function transferGovernorship(address _proposedGovernor) external; function unpause() external; function updateFeeCollector(address _newFeeCollector) external; function updatePoolRewards(address _newPoolRewards) external; function updateWithdrawFee(uint256 _newWithdrawFee) external; function whitelistedWithdraw(uint256 _shares) external; function withdraw(uint256 _shares) external; function withdrawFee() external view returns (uint256); } // File contracts/Staking/FraxUnifiedFarm_ERC20.sol // ==================================================================== // | ______ _______ | // | / _____________ __ __ / ____(_____ ____ _____ ________ | // | / /_ / ___/ __ `| |/_/ / /_ / / __ \/ __ `/ __ \/ ___/ _ \ | // | / __/ / / / /_/ _> < / __/ / / / / / /_/ / / / / /__/ __/ | // | /_/ /_/ \__,_/_/|_| /_/ /_/_/ /_/\__,_/_/ /_/\___/\___/ | // | | // ==================================================================== // ======================= FraxUnifiedFarm_ERC20 ====================== // ==================================================================== // For ERC20 Tokens // Uses FraxUnifiedFarmTemplate.sol // -------------------- VARIES -------------------- // G-UNI // import "../Misc_AMOs/gelato/IGUniPool.sol"; // mStable // import '../Misc_AMOs/mstable/IFeederPool.sol'; // // StakeDAO sdETH-FraxPut // import '../Misc_AMOs/stakedao/IOpynPerpVault.sol'; // StakeDAO Vault // import '../Misc_AMOs/stakedao/IStakeDaoVault.sol'; // Uniswap V2 // import '../Uniswap/Interfaces/IUniswapV2Pair.sol'; // Vesper // ------------------------------------------------ contract FraxUnifiedFarm_ERC20 is FraxUnifiedFarmTemplate { /* ========== STATE VARIABLES ========== */ // -------------------- VARIES -------------------- // G-UNI // IGUniPool public stakingToken; // mStable // IFeederPool public stakingToken; // sdETH-FraxPut Vault // IOpynPerpVault public stakingToken; // StakeDAO Vault // IStakeDaoVault public stakingToken; // Uniswap V2 // IUniswapV2Pair public stakingToken; // Vesper IVPool public stakingToken; // ------------------------------------------------ // Stake tracking mapping(address => LockedStake[]) public lockedStakes; /* ========== STRUCTS ========== */ // Struct for the stake struct LockedStake { bytes32 kek_id; uint256 start_timestamp; uint256 liquidity; uint256 ending_timestamp; uint256 lock_multiplier; // 6 decimals of precision. 1x = 1000000 } /* ========== CONSTRUCTOR ========== */ constructor ( address _owner, address[] memory _rewardTokens, address[] memory _rewardManagers, uint256[] memory _rewardRatesManual, address[] memory _gaugeControllers, address[] memory _rewardDistributors, address _stakingToken ) FraxUnifiedFarmTemplate(_owner, _rewardTokens, _rewardManagers, _rewardRatesManual, _gaugeControllers, _rewardDistributors) { // -------------------- VARIES -------------------- // G-UNI // stakingToken = IGUniPool(_stakingToken); // address token0 = address(stakingToken.token0()); // frax_is_token0 = token0 == frax_address; // mStable // stakingToken = IFeederPool(_stakingToken); // StakeDAO sdETH-FraxPut Vault // stakingToken = IOpynPerpVault(_stakingToken); // StakeDAO Vault // stakingToken = IStakeDaoVault(_stakingToken); // Uniswap V2 // stakingToken = IUniswapV2Pair(_stakingToken); // address token0 = stakingToken.token0(); // if (token0 == frax_address) frax_is_token0 = true; // else frax_is_token0 = false; // Vesper stakingToken = IVPool(_stakingToken); // ------------------------------------------------ } /* ============= VIEWS ============= */ // ------ FRAX RELATED ------ function fraxPerLPToken() public view override returns (uint256) { // Get the amount of FRAX 'inside' of the lp tokens uint256 frax_per_lp_token; // G-UNI // ============================================ // { // (uint256 reserve0, uint256 reserve1) = stakingToken.getUnderlyingBalances(); // uint256 total_frax_reserves = frax_is_token0 ? reserve0 : reserve1; // frax_per_lp_token = (total_frax_reserves * 1e18) / stakingToken.totalSupply(); // } // mStable // ============================================ // { // uint256 total_frax_reserves; // (, IFeederPool.BassetData memory vaultData) = (stakingToken.getBasset(frax_address)); // total_frax_reserves = uint256(vaultData.vaultBalance); // frax_per_lp_token = (total_frax_reserves * 1e18) / stakingToken.totalSupply(); // } // StakeDAO sdETH-FraxPut Vault // ============================================ // { // uint256 frax3crv_held = stakingToken.totalUnderlyingControlled(); // // Optimistically assume 50/50 FRAX/3CRV ratio in the metapool to save gas // frax_per_lp_token = ((frax3crv_held * 1e18) / stakingToken.totalSupply()) / 2; // } // StakeDAO Vault // ============================================ // { // uint256 frax3crv_held = stakingToken.balance(); // // Optimistically assume 50/50 FRAX/3CRV ratio in the metapool to save gas // frax_per_lp_token = ((frax3crv_held * 1e18) / stakingToken.totalSupply()) / 2; // } // Uniswap V2 // ============================================ // { // uint256 total_frax_reserves; // (uint256 reserve0, uint256 reserve1, ) = (stakingToken.getReserves()); // if (frax_is_token0) total_frax_reserves = reserve0; // else total_frax_reserves = reserve1; // frax_per_lp_token = (total_frax_reserves * 1e18) / stakingToken.totalSupply(); // } // Vesper // ============================================ frax_per_lp_token = stakingToken.pricePerShare(); return frax_per_lp_token; } // ------ LIQUIDITY AND WEIGHTS ------ // Calculated the combined weight for an account function calcCurCombinedWeight(address account) public override view returns ( uint256 old_combined_weight, uint256 new_vefxs_multiplier, uint256 new_combined_weight ) { // Get the old combined weight old_combined_weight = _combined_weights[account]; // Get the veFXS multipliers // For the calculations, use the midpoint (analogous to midpoint Riemann sum) new_vefxs_multiplier = veFXSMultiplier(account); uint256 midpoint_vefxs_multiplier; if (_locked_liquidity[account] == 0 && _combined_weights[account] == 0) { // This is only called for the first stake to make sure the veFXS multiplier is not cut in half midpoint_vefxs_multiplier = new_vefxs_multiplier; } else { midpoint_vefxs_multiplier = (new_vefxs_multiplier + _vefxsMultiplierStored[account]) / 2; } // Loop through the locked stakes, first by getting the liquidity * lock_multiplier portion new_combined_weight = 0; for (uint256 i = 0; i < lockedStakes[account].length; i++) { LockedStake memory thisStake = lockedStakes[account][i]; uint256 lock_multiplier = thisStake.lock_multiplier; // If the lock is expired if (thisStake.ending_timestamp <= block.timestamp) { // If the lock expired in the time since the last claim, the weight needs to be proportionately averaged this time if (lastRewardClaimTime[account] < thisStake.ending_timestamp){ uint256 time_before_expiry = thisStake.ending_timestamp - lastRewardClaimTime[account]; uint256 time_after_expiry = block.timestamp - thisStake.ending_timestamp; // Get the weighted-average lock_multiplier uint256 numerator = (lock_multiplier * time_before_expiry) + (MULTIPLIER_PRECISION * time_after_expiry); lock_multiplier = numerator / (time_before_expiry + time_after_expiry); } // Otherwise, it needs to just be 1x else { lock_multiplier = MULTIPLIER_PRECISION; } } uint256 liquidity = thisStake.liquidity; uint256 combined_boosted_amount = (liquidity * (lock_multiplier + midpoint_vefxs_multiplier)) / MULTIPLIER_PRECISION; new_combined_weight = new_combined_weight + combined_boosted_amount; } } // ------ LOCK RELATED ------ // All the locked stakes for a given account function lockedStakesOf(address account) external view returns (LockedStake[] memory) { return lockedStakes[account]; } // Returns the length of the locked stakes for a given account function lockedStakesOfLength(address account) external view returns (uint256) { return lockedStakes[account].length; } // // All the locked stakes for a given account [old-school method] // function lockedStakesOfMultiArr(address account) external view returns ( // bytes32[] memory kek_ids, // uint256[] memory start_timestamps, // uint256[] memory liquidities, // uint256[] memory ending_timestamps, // uint256[] memory lock_multipliers // ) { // for (uint256 i = 0; i < lockedStakes[account].length; i++){ // LockedStake memory thisStake = lockedStakes[account][i]; // kek_ids[i] = thisStake.kek_id; // start_timestamps[i] = thisStake.start_timestamp; // liquidities[i] = thisStake.liquidity; // ending_timestamps[i] = thisStake.ending_timestamp; // lock_multipliers[i] = thisStake.lock_multiplier; // } // } /* =============== MUTATIVE FUNCTIONS =============== */ // ------ STAKING ------ function _getStake(address staker_address, bytes32 kek_id) internal view returns (LockedStake memory locked_stake, uint256 arr_idx) { for (uint256 i = 0; i < lockedStakes[staker_address].length; i++){ if (kek_id == lockedStakes[staker_address][i].kek_id){ locked_stake = lockedStakes[staker_address][i]; arr_idx = i; break; } } require(locked_stake.kek_id == kek_id, "Stake not found"); } // Add additional LPs to an existing locked stake function lockAdditional(bytes32 kek_id, uint256 addl_liq) updateRewardAndBalance(msg.sender, true) public { // Get the stake and its index (LockedStake memory thisStake, uint256 theArrayIndex) = _getStake(msg.sender, kek_id); // Calculate the new amount uint256 new_amt = thisStake.liquidity + addl_liq; // Checks require(addl_liq >= 0, "Must be nonzero"); // Pull the tokens from the sender TransferHelper.safeTransferFrom(address(stakingToken), msg.sender, address(this), addl_liq); // Update the stake lockedStakes[msg.sender][theArrayIndex] = LockedStake( kek_id, thisStake.start_timestamp, new_amt, thisStake.ending_timestamp, thisStake.lock_multiplier ); // Update liquidities _total_liquidity_locked += addl_liq; _locked_liquidity[msg.sender] += addl_liq; { address the_proxy = staker_designated_proxies[msg.sender]; if (the_proxy != address(0)) proxy_lp_balances[the_proxy] += addl_liq; } // Need to call to update the combined weights _updateRewardAndBalance(msg.sender, false); } // Two different stake functions are needed because of delegateCall and msg.sender issues (important for migration) function stakeLocked(uint256 liquidity, uint256 secs) nonReentrant external { _stakeLocked(msg.sender, msg.sender, liquidity, secs, block.timestamp); } function _stakeLockedInternalLogic( address source_address, uint256 liquidity ) internal virtual { revert("Need _stakeLockedInternalLogic logic"); } // If this were not internal, and source_address had an infinite approve, this could be exploitable // (pull funds from source_address and stake for an arbitrary staker_address) function _stakeLocked( address staker_address, address source_address, uint256 liquidity, uint256 secs, uint256 start_timestamp ) internal updateRewardAndBalance(staker_address, true) { require(stakingPaused == false || valid_migrators[msg.sender] == true, "Staking paused or in migration"); require(secs >= lock_time_min, "Minimum stake time not met"); require(secs <= lock_time_for_max_multiplier,"Trying to lock for too long"); // Pull in the required token(s) // Varies per farm TransferHelper.safeTransferFrom(address(stakingToken), source_address, address(this), liquidity); // Get the lock multiplier and kek_id uint256 lock_multiplier = lockMultiplier(secs); bytes32 kek_id = keccak256(abi.encodePacked(staker_address, start_timestamp, liquidity, _locked_liquidity[staker_address])); // Create the locked stake lockedStakes[staker_address].push(LockedStake( kek_id, start_timestamp, liquidity, start_timestamp + secs, lock_multiplier )); // Update liquidities _total_liquidity_locked += liquidity; _locked_liquidity[staker_address] += liquidity; { address the_proxy = staker_designated_proxies[staker_address]; if (the_proxy != address(0)) proxy_lp_balances[the_proxy] += liquidity; } // Need to call again to make sure everything is correct _updateRewardAndBalance(staker_address, false); emit StakeLocked(staker_address, liquidity, secs, kek_id, source_address); } // ------ WITHDRAWING ------ // Two different withdrawLocked functions are needed because of delegateCall and msg.sender issues (important for migration) function withdrawLocked(bytes32 kek_id, address destination_address) nonReentrant external { require(withdrawalsPaused == false, "Withdrawals paused"); _withdrawLocked(msg.sender, destination_address, kek_id); } // No withdrawer == msg.sender check needed since this is only internally callable and the checks are done in the wrapper // functions like migrator_withdraw_locked() and withdrawLocked() function _withdrawLocked( address staker_address, address destination_address, bytes32 kek_id ) internal { // Collect rewards first and then update the balances _getReward(staker_address, destination_address); // Get the stake and its index (LockedStake memory thisStake, uint256 theArrayIndex) = _getStake(staker_address, kek_id); require(block.timestamp >= thisStake.ending_timestamp || stakesUnlocked == true || valid_migrators[msg.sender] == true, "Stake is still locked!"); uint256 liquidity = thisStake.liquidity; if (liquidity > 0) { // Update liquidities _total_liquidity_locked = _total_liquidity_locked - liquidity; _locked_liquidity[staker_address] = _locked_liquidity[staker_address] - liquidity; { address the_proxy = staker_designated_proxies[staker_address]; if (the_proxy != address(0)) proxy_lp_balances[the_proxy] -= liquidity; } // Remove the stake from the array delete lockedStakes[staker_address][theArrayIndex]; // Give the tokens to the destination_address // Should throw if insufficient balance stakingToken.transfer(destination_address, liquidity); // Need to call again to make sure everything is correct _updateRewardAndBalance(staker_address, false); emit WithdrawLocked(staker_address, liquidity, kek_id, destination_address); } } function _getRewardExtraLogic(address rewardee, address destination_address) internal override { // Do nothing } /* ========== RESTRICTED FUNCTIONS - Curator / migrator callable ========== */ // Migrator can stake for someone else (they won't be able to withdraw it back though, only staker_address can). function migrator_stakeLocked_for(address staker_address, uint256 amount, uint256 secs, uint256 start_timestamp) external isMigrating { require(staker_allowed_migrators[staker_address][msg.sender] && valid_migrators[msg.sender], "Mig. invalid or unapproved"); _stakeLocked(staker_address, msg.sender, amount, secs, start_timestamp); } // Used for migrations function migrator_withdraw_locked(address staker_address, bytes32 kek_id) external isMigrating { require(staker_allowed_migrators[staker_address][msg.sender] && valid_migrators[msg.sender], "Mig. invalid or unapproved"); _withdrawLocked(staker_address, msg.sender, kek_id); } /* ========== RESTRICTED FUNCTIONS - Owner or timelock only ========== */ // Inherited... /* ========== EVENTS ========== */ event StakeLocked(address indexed user, uint256 amount, uint256 secs, bytes32 kek_id, address source_address); event WithdrawLocked(address indexed user, uint256 liquidity, bytes32 kek_id, address destination_address); } // File contracts/Staking/Variants/FraxUnifiedFarm_ERC20_Vesper_Orbit_FRAX.sol contract FraxUnifiedFarm_ERC20_Vesper_Orbit_FRAX is FraxUnifiedFarm_ERC20 { constructor ( address _owner, address[] memory _rewardTokens, address[] memory _rewardManagers, uint256[] memory _rewardRates, address[] memory _gaugeControllers, address[] memory _rewardDistributors, address _stakingToken ) FraxUnifiedFarm_ERC20(_owner , _rewardTokens, _rewardManagers, _rewardRates, _gaugeControllers, _rewardDistributors, _stakingToken) {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address[]","name":"_rewardTokens","type":"address[]"},{"internalType":"address[]","name":"_rewardManagers","type":"address[]"},{"internalType":"uint256[]","name":"_rewardRates","type":"uint256[]"},{"internalType":"address[]","name":"_gaugeControllers","type":"address[]"},{"internalType":"address[]","name":"_rewardDistributors","type":"address[]"},{"internalType":"address","name":"_stakingToken","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldOwner","type":"address"},{"indexed":false,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnerChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnerNominated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"secs","type":"uint256"},{"indexed":false,"internalType":"bytes32","name":"kek_id","type":"bytes32"},{"indexed":false,"internalType":"address","name":"source_address","type":"address"}],"name":"StakeLocked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"liquidity","type":"uint256"},{"indexed":false,"internalType":"bytes32","name":"kek_id","type":"bytes32"},{"indexed":false,"internalType":"address","name":"destination_address","type":"address"}],"name":"WithdrawLocked","type":"event"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"calcCurCombinedWeight","outputs":[{"internalType":"uint256","name":"old_combined_weight","type":"uint256"},{"internalType":"uint256","name":"new_vefxs_multiplier","type":"uint256"},{"internalType":"uint256","name":"new_combined_weight","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"reward_token_address","type":"address"},{"internalType":"address","name":"new_manager_address","type":"address"}],"name":"changeTokenManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"combinedWeightOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"earned","outputs":[{"internalType":"uint256[]","name":"new_earned","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"fraxPerLPToken","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getAllRewardTokens","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"destination_address","type":"address"}],"name":"getReward","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getRewardForDuration","outputs":[{"internalType":"uint256[]","name":"rewards_per_duration_arr","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"caller_addr","type":"address"},{"internalType":"address","name":"reward_token_addr","type":"address"}],"name":"isTokenManagerFor","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastUpdateTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"kek_id","type":"bytes32"},{"internalType":"uint256","name":"addl_liq","type":"uint256"}],"name":"lockAdditional","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"secs","type":"uint256"}],"name":"lockMultiplier","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lock_max_multiplier","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lock_time_for_max_multiplier","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lock_time_min","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"lockedLiquidityOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"lockedStakes","outputs":[{"internalType":"bytes32","name":"kek_id","type":"bytes32"},{"internalType":"uint256","name":"start_timestamp","type":"uint256"},{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"ending_timestamp","type":"uint256"},{"internalType":"uint256","name":"lock_multiplier","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"lockedStakesOf","outputs":[{"components":[{"internalType":"bytes32","name":"kek_id","type":"bytes32"},{"internalType":"uint256","name":"start_timestamp","type":"uint256"},{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"ending_timestamp","type":"uint256"},{"internalType":"uint256","name":"lock_multiplier","type":"uint256"}],"internalType":"struct FraxUnifiedFarm_ERC20.LockedStake[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"lockedStakesOfLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"maxLPForMaxBoost","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"staker_address","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"secs","type":"uint256"},{"internalType":"uint256","name":"start_timestamp","type":"uint256"}],"name":"migrator_stakeLocked_for","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"staker_address","type":"address"},{"internalType":"bytes32","name":"kek_id","type":"bytes32"}],"name":"migrator_withdraw_locked","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"minVeFXSForMaxBoost","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"proxy_address","type":"address"}],"name":"minVeFXSForMaxBoostProxy","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"nominateNewOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"nominatedOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"periodFinish","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"proxy_address","type":"address"}],"name":"proxyStakedFrax","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"staker_address","type":"address"}],"name":"proxyToggleStaker","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"proxy_lp_balances","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"tokenAddress","type":"address"},{"internalType":"uint256","name":"tokenAmount","type":"uint256"}],"name":"recoverERC20","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"rewardManagers","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"token_idx","type":"uint256"}],"name":"rewardRates","outputs":[{"internalType":"uint256","name":"rwd_rate","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"rewardTokenAddrToIdx","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rewardsDuration","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rewardsPerToken","outputs":[{"internalType":"uint256[]","name":"newRewardsPerTokenStored","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[6]","name":"_misc_vars","type":"uint256[6]"}],"name":"setMiscVariables","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_stakingPaused","type":"bool"},{"internalType":"bool","name":"_withdrawalsPaused","type":"bool"},{"internalType":"bool","name":"_rewardsCollectionPaused","type":"bool"}],"name":"setPauses","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"reward_token_address","type":"address"},{"internalType":"uint256","name":"_new_rate","type":"uint256"},{"internalType":"address","name":"_gauge_controller_address","type":"address"},{"internalType":"address","name":"_rewards_distributor_address","type":"address"}],"name":"setRewardVars","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"secs","type":"uint256"}],"name":"stakeLocked","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"proxy_address","type":"address"}],"name":"stakerSetVeFXSProxy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"migrator_address","type":"address"}],"name":"stakerToggleMigrator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"staker_designated_proxies","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"stakesUnlocked","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"stakingToken","outputs":[{"internalType":"contract IVPool","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"sync","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"force_update","type":"bool"}],"name":"sync_gauge_weights","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"toggleMigrations","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"migrator_address","type":"address"}],"name":"toggleMigrator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_proxy_addr","type":"address"}],"name":"toggleValidVeFXSProxy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"totalCombinedWeight","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalLiquidityLocked","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unlockStakes","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"userStakedFrax","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"veFXSMultiplier","outputs":[{"internalType":"uint256","name":"vefxs_multiplier","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"vefxs_boost_scale_factor","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"vefxs_max_multiplier","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"vefxs_per_frax_for_max_boost","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"kek_id","type":"bytes32"},{"internalType":"address","name":"destination_address","type":"address"}],"name":"withdrawLocked","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
6080604052600380546001600160a01b03191673c8418af6358ffdda74e09ca9cc3fe03ca6adc5b01790556729a2241af62c00006007556305a39a8060085562015180600955673782dace9d900000600a55671bc16d674ec80000600b819055600c553480156200006f57600080fd5b50604051620052a4380380620052a48339810160408190526200009291620005ae565b86868686868686868686868686856001600160a01b038116620000fb5760405162461bcd60e51b815260206004820152601960248201527f4f776e657220616464726573732063616e6e6f74206265203000000000000000604482015260640160405180910390fd5b600080546001600160a01b0319166001600160a01b03831690811782556040805192835260208301919091527fb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159c910160405180910390a150600160025584516200016d90601190602088019062000385565b5081516200018390601290602085019062000385565b5080516200019990601390602084019062000385565b508251620001af906014906020860190620003ef565b5060005b85518110156200031a578060156000888481518110620001d757620001d7620006b5565b6020908102919091018101516001600160a01b03168252810191909152604001600090812091909155601680546001810182559082527fd833147d7dc355ba459fc788f669e58cfaf9dc25ddcd0702e87d69c7b512428901558451859082908110620002475762000247620006b5565b602002602001015160106000888481518110620002685762000268620006b5565b6020908102919091018101516001600160a01b03908116835290820192909252604001600090812080546001600160a01b03191693909216929092179055601a805460018181019092557f057c384a7d1c54f3a1b2e5e67b2617b8224fdfd1ea7234eea573a6ff665ff63e01829055601b8054918201815582527f3ad8aa4f87544323a9d1e5dd902f40c356527a7955687113db5f9a85ad579dc10155806200031181620006e1565b915050620001b3565b506024805460ff191690554260068190556200033b9062093a8090620006ff565b6005555050602480546001600160a01b039096166501000000000002600160281b600160c81b031990961695909517909455506200071a9f50505050505050505050505050505050565b828054828255906000526020600020908101928215620003dd579160200282015b82811115620003dd57825182546001600160a01b0319166001600160a01b03909116178255602090920191600190910190620003a6565b50620003eb9291506200042d565b5090565b828054828255906000526020600020908101928215620003dd579160200282015b82811115620003dd57825182559160200191906001019062000410565b5b80821115620003eb57600081556001016200042e565b80516001600160a01b03811681146200045c57600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b0381118282101715620004a257620004a262000461565b604052919050565b60006001600160401b03821115620004c657620004c662000461565b5060051b60200190565b600082601f830112620004e257600080fd5b81516020620004fb620004f583620004aa565b62000477565b82815260059290921b840181019181810190868411156200051b57600080fd5b8286015b848110156200054157620005338162000444565b83529183019183016200051f565b509695505050505050565b600082601f8301126200055e57600080fd5b8151602062000571620004f583620004aa565b82815260059290921b840181019181810190868411156200059157600080fd5b8286015b8481101562000541578051835291830191830162000595565b600080600080600080600060e0888a031215620005ca57600080fd5b620005d58862000444565b60208901519097506001600160401b0380821115620005f357600080fd5b620006018b838c01620004d0565b975060408a01519150808211156200061857600080fd5b620006268b838c01620004d0565b965060608a01519150808211156200063d57600080fd5b6200064b8b838c016200054c565b955060808a01519150808211156200066257600080fd5b620006708b838c01620004d0565b945060a08a01519150808211156200068757600080fd5b50620006968a828b01620004d0565b925050620006a760c0890162000444565b905092959891949750929550565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b6000600019821415620006f857620006f8620006cb565b5060010190565b60008219821115620007155762000715620006cb565b500190565b614b7a806200072a6000396000f3fe608060405234801561001057600080fd5b50600436106103ae5760003560e01c80638da5cb5b116101f4578063d5e1a9c61161011a578063eb3c209e116100ad578063f2caeb1e1161007c578063f2caeb1e146108dc578063f77e34d1146108ef578063facefb6414610902578063fff6cae91461091557600080fd5b8063eb3c209e146108ae578063ebe2b12b146108c1578063f288baf6146108ca578063f2a8d349146108d357600080fd5b8063e01f62bf116100e9578063e01f62bf14610878578063e1ba95d214610880578063e44b9fa514610888578063e7f305821461089b57600080fd5b8063d5e1a9c614610809578063d7400d561461081c578063d9f96e8d1461082f578063de1a65511461086557600080fd5b8063b85efd0611610192578063ca6df29d11610161578063ca6df29d146107a4578063cc2abd64146107da578063cdc82e80146107ed578063d42fc9b4146107f657600080fd5b8063b85efd061461076c578063b94c4dcb1461077f578063c00007b014610788578063c8f33c911461079b57600080fd5b8063a0f23476116101ce578063a0f2347614610735578063a2217bc514610748578063aa1d4fce14610750578063affaa7a41461075957600080fd5b80638da5cb5b146106f557806391cf600a146107155780639637927f1461072857600080fd5b806341a16f3f116102d957806370641a36116102775780637d6ef08e116102465780637d6ef08e146106825780637f472e54146106a15780638980f11f146106b45780638bad86a7146106c757600080fd5b806370641a361461060e57806372f702f3146106165780637970833e1461063f57806379ba50971461067a57600080fd5b80635bfd9258116102b35780635bfd9258146105d557806364f2c060146105dd57806369339245146105e55780636e27cef91461060557600080fd5b806341a16f3f1461056c5780634fd2b536146105a257806353a47bb7146105b557600080fd5b80631face856116103515780632c0c2a0a116103205780632c0c2a0a146105065780633650aff21461051957806336f89af21461052c578063386a95251461056257600080fd5b80631face85614610462578063231b68dc1461047557806328408bab1461049857806328ef934e146104f357600080fd5b80631627540c1161038d5780631627540c1461041257806317b18c89146104275780631c1f78eb1461043a5780631e090f011461044257600080fd5b80628cc262146103b35780630d7bac4f146103dc57806312edb24c146103fd575b600080fd5b6103c66103c136600461456d565b61091d565b6040516103d39190614588565b60405180910390f35b6103ef6103ea3660046145cc565b610a9c565b6040519081526020016103d3565b610405610aec565b6040516103d391906145e5565b61042561042036600461456d565b610b5b565b005b610425610435366004614633565b610c80565b6103c6610d06565b61045561045036600461456d565b610da7565b6040516103d39190614655565b6103ef61047036600461456d565b610e5b565b6104886104833660046146c3565b610ea0565b60405190151581526020016103d3565b6104ce6104a636600461456d565b60236020526000908152604090205473ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016103d3565b6104256105013660046146f6565b610f0f565b6103ef61051436600461456d565b61104e565b61042561052736600461456d565b611333565b6103ef61053a36600461456d565b73ffffffffffffffffffffffffffffffffffffffff166000908152601f602052604090205490565b6103ef62093a8081565b6104ce61057a36600461456d565b60106020526000908152604090205473ffffffffffffffffffffffffffffffffffffffff1681565b6103ef6105b036600461456d565b611426565b6001546104ce9073ffffffffffffffffffffffffffffffffffffffff1681565b6103ef611447565b601d546103ef565b6103ef6105f336600461456d565b60156020526000908152604090205481565b6103ef60095481565b6103c66114db565b6024546104ce9065010000000000900473ffffffffffffffffffffffffffffffffffffffff1681565b61065261064d36600461472f565b61163a565b604080519586526020860194909452928401919091526060830152608082015260a0016103d3565b610425611688565b6103ef61069036600461456d565b602080526000908152604090205481565b6103ef6106af36600461456d565b6117d3565b6104256106c236600461472f565b6117ea565b6106da6106d536600461456d565b6119ce565b604080519384526020840192909252908201526060016103d3565b6000546104ce9073ffffffffffffffffffffffffffffffffffffffff1681565b61042561072336600461456d565b611c9c565b6024546104889060ff1681565b6103ef61074336600461456d565b611d8f565b610425611e4a565b6103ef600a5481565b61042561076736600461456d565b611f23565b61042561077a366004614633565b612013565b6103ef60085481565b6103c661079636600461456d565b6121be565b6103ef60065481565b6103ef6107b236600461456d565b73ffffffffffffffffffffffffffffffffffffffff1660009081526025602052604090205490565b6104256107e8366004614767565b6122b9565b6103ef60075481565b6103ef61080436600461456d565b6123f2565b6104256108173660046147b2565b61242e565b61042561082a36600461456d565b61261d565b6103ef61083d36600461456d565b73ffffffffffffffffffffffffffffffffffffffff166000908152601e602052604090205490565b6104256108733660046146c3565b6127c2565b601c546103ef565b6104256128a9565b6104256108963660046147ff565b61297a565b6104256108a936600461456d565b612a68565b6104256108bc36600461472f565b612bc3565b6103ef60055481565b6103ef600b5481565b6103ef600c5481565b6103ef6108ea3660046145cc565b612cfe565b6104256108fd366004614822565b612e15565b61042561091036600461486e565b612fe7565b6104256131a7565b606060006109296114db565b60115490915067ffffffffffffffff8111156109475761094761483f565b604051908082528060200260200182016040528015610970578160200160208202803683370190505b5073ffffffffffffffffffffffffffffffffffffffff84166000908152601f602052604090205490925015610a965760005b601154811015610a945773ffffffffffffffffffffffffffffffffffffffff84166000818152601860209081526040808320858452825280832054938352601782528083208584529091529020548351670de0b6b3a76400009190859085908110610a0f57610a0f614913565b6020026020010151610a219190614971565b73ffffffffffffffffffffffffffffffffffffffff87166000908152601f6020526040902054610a519190614988565b610a5b91906149c5565b610a659190614a00565b838281518110610a7757610a77614913565b602090810291909101015280610a8c81614a18565b9150506109a2565b505b50919050565b600754600854600091610ae691610abb670de0b6b3a764000083614971565b610ac59086614988565b610acf91906149c5565b610ae190670de0b6b3a7640000614a00565b6131cc565b92915050565b60606011805480602002602001604051908101604052809291908181526020018280548015610b5157602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff168152600190910190602001808311610b26575b5050505050905090565b60005473ffffffffffffffffffffffffffffffffffffffff163314610c07576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602f60248201527f4f6e6c792074686520636f6e7472616374206f776e6572206d6179207065726660448201527f6f726d207468697320616374696f6e000000000000000000000000000000000060648201526084015b60405180910390fd5b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040519081527f906a1c6bd7e3091ea86693dd029a831c19049ce77f1dce2ce0bab1cacbabce229060200160405180910390a150565b600280541415610cec576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610bfe565b60028055610cfd33808484426131e4565b50506001600255565b60145460609067ffffffffffffffff811115610d2457610d2461483f565b604051908082528060200260200182016040528015610d4d578160200160208202803683370190505b50905060005b601454811015610da35762093a80610d6a82612cfe565b610d749190614988565b828281518110610d8657610d86614913565b602090810291909101015280610d9b81614a18565b915050610d53565b5090565b73ffffffffffffffffffffffffffffffffffffffff81166000908152602560209081526040808320805482518185028101850190935280835260609492939192909184015b82821015610e5057838290600052602060002090600502016040518060a00160405290816000820154815260200160018201548152602001600282015481526020016003820154815260200160048201548152505081526020019060010190610dec565b505050509050919050565b73ffffffffffffffffffffffffffffffffffffffff81166000908152602080526040812054600454670de0b6b3a764000091610e9691614988565b610ae691906149c5565b6000805473ffffffffffffffffffffffffffffffffffffffff84811691161415610ecc57506001610ae6565b73ffffffffffffffffffffffffffffffffffffffff82811660009081526010602052604090205481169084161415610f0657506001610ae6565b50600092915050565b60245460ff610100909104161515600114610f86576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f4e6f7420696e206d6967726174696f6e000000000000000000000000000000006044820152606401610bfe565b73ffffffffffffffffffffffffffffffffffffffff8416600090815260226020908152604080832033845290915290205460ff168015610fd557503360009081526021602052604090205460ff165b61103b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f4d69672e20696e76616c6964206f7220756e617070726f7665640000000000006044820152606401610bfe565b61104884338585856131e4565b50505050565b73ffffffffffffffffffffffffffffffffffffffff80821660009081526023602052604081205490918291168015611119576003546040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8381166004830152909116906370a0823190602401602060405180830381865afa1580156110f0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111149190614a51565b6111ad565b6003546040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8681166004830152909116906370a0823190602401602060405180830381865afa158015611189573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111ad9190614a51565b91506000670de0b6b3a7640000600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611227573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061124b9190614a51565b6112559190614988565b600a54600b546112659086614988565b61126f9190614988565b61127991906149c5565b905060008073ffffffffffffffffffffffffffffffffffffffff8416156112a8576112a3846117d3565b6112b1565b6112b187611426565b90508015611303576000816112ce670de0b6b3a764000088614988565b6112d891906149c5565b9050670de0b6b3a7640000600b54826112f19190614988565b6112fb91906149c5565b925050611308565b600091505b508082116113165780611318565b815b9450600b5485111561132a57600b5494505b50505050919050565b60005473ffffffffffffffffffffffffffffffffffffffff1633148061136c5750738412ebf45bac1b340bbe8f318b928c466c4e39ca33145b6113d2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b00000000000000000000006044820152606401610bfe565b73ffffffffffffffffffffffffffffffffffffffff16600090815260216020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00811660ff90911615179055565b6000670de0b6b3a7640000600c5461143d846123f2565b610e969190614988565b600080602460059054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166399530b066040518163ffffffff1660e01b8152600401602060405180830381865afa1580156114b7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ae69190614a51565b6060601c54600014806114ee5750601d54155b15611548576016805480602002602001604051908101604052809291908181526020018280548015610b5157602002820191906000526020600020905b81548152602001906001019080831161152b575050505050905090565b60115467ffffffffffffffff8111156115635761156361483f565b60405190808252806020026020018201604052801561158c578160200160208202803683370190505b50905060005b601654811015610da357601d546115a882612cfe565b6006546115b361360b565b6115bd9190614971565b6115c79190614988565b6115d990670de0b6b3a7640000614988565b6115e391906149c5565b601682815481106115f6576115f6614913565b906000526020600020015461160b9190614a00565b82828151811061161d5761161d614913565b60209081029190910101528061163281614a18565b915050611592565b6025602052816000526040600020818154811061165657600080fd5b600091825260209091206005909102018054600182015460028301546003840154600490940154929550909350919085565b60015473ffffffffffffffffffffffffffffffffffffffff16331461172f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603560248201527f596f75206d757374206265206e6f6d696e61746564206265666f726520796f7560448201527f2063616e20616363657074206f776e65727368697000000000000000000000006064820152608401610bfe565b6000546001546040805173ffffffffffffffffffffffffffffffffffffffff93841681529290911660208301527fb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159c910160405180910390a160018054600080547fffffffffffffffffffffffff000000000000000000000000000000000000000090811673ffffffffffffffffffffffffffffffffffffffff841617909155169055565b6000670de0b6b3a7640000600c5461143d84610e5b565b600054829073ffffffffffffffffffffffffffffffffffffffff1633148061181757506118173382610ea0565b61187d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f4e6f74206f776e6572206f7220746b6e206d67720000000000000000000000006044820152606401610bfe565b6000805b6011548110156118f8578473ffffffffffffffffffffffffffffffffffffffff16601182815481106118b5576118b5614913565b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff1614156118e657600191506118f8565b806118f081614a18565b915050611881565b5080801561192c575073ffffffffffffffffffffffffffffffffffffffff8481166000908152601060205260409020541633145b80611957575080158015611957575060005473ffffffffffffffffffffffffffffffffffffffff1633145b156119675761104884338561361e565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f4e6f2076616c696420746f6b656e7320746f207265636f7665720000000000006044820152606401610bfe565b505050565b73ffffffffffffffffffffffffffffffffffffffff81166000908152601f602052604081205490806119ff8461104e565b73ffffffffffffffffffffffffffffffffffffffff85166000908152601e602052604081205491935090158015611a59575073ffffffffffffffffffffffffffffffffffffffff85166000908152601f6020526040902054155b15611a65575081611aa5565b73ffffffffffffffffffffffffffffffffffffffff85166000908152600d6020526040902054600290611a989085614a00565b611aa291906149c5565b90505b6000915060005b73ffffffffffffffffffffffffffffffffffffffff8616600090815260256020526040902054811015611c935773ffffffffffffffffffffffffffffffffffffffff86166000908152602560205260408120805483908110611b1057611b10614913565b90600052602060002090600502016040518060a001604052908160008201548152602001600182015481526020016002820154815260200160038201548152602001600482015481525050905060008160800151905042826060015111611c4057606082015173ffffffffffffffffffffffffffffffffffffffff89166000908152601960205260409020541015611c355773ffffffffffffffffffffffffffffffffffffffff88166000908152601960205260408120546060840151611bd79190614971565b90506000836060015142611beb9190614971565b90506000611c0182670de0b6b3a7640000614988565b611c0b8486614988565b611c159190614a00565b9050611c218284614a00565b611c2b90826149c5565b9350505050611c40565b50670de0b6b3a76400005b60408201516000670de0b6b3a7640000611c5a8785614a00565b611c649084614988565b611c6e91906149c5565b9050611c7a8188614a00565b9650505050508080611c8b90614a18565b915050611aac565b50509193909250565b60005473ffffffffffffffffffffffffffffffffffffffff16331480611cd55750738412ebf45bac1b340bbe8f318b928c466c4e39ca33145b611d3b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b00000000000000000000006044820152606401610bfe565b73ffffffffffffffffffffffffffffffffffffffff166000908152600e6020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00811660ff90911615179055565b6000600454600c54611da19190614988565b6003546040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8581166004830152670de0b6b3a76400009283929116906370a0823190602401602060405180830381865afa158015611e1c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e409190614a51565b61143d9190614988565b60005473ffffffffffffffffffffffffffffffffffffffff16331480611e835750738412ebf45bac1b340bbe8f318b928c466c4e39ca33145b611ee9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b00000000000000000000006044820152606401610bfe565b602480547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff81166101009182900460ff1615909102179055565b73ffffffffffffffffffffffffffffffffffffffff811660009081526021602052604090205460ff16611fb2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f496e76616c6964206d69677261746f72206164647265737300000000000000006044820152606401610bfe565b33600090815260226020908152604080832073ffffffffffffffffffffffffffffffffffffffff94909416835292905220805460ff8116157fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00909116179055565b336001612020828261378e565b60008061202d33876138b0565b9150915060008583604001516120439190614a00565b90506024546120739065010000000000900473ffffffffffffffffffffffffffffffffffffffff16333089613a76565b6040805160a0810182528881526020858101518183015281830184905260608087015190830152608080870151908301523360009081526025909152919091208054849081106120c5576120c5614913565b9060005260206000209060050201600082015181600001556020820151816001015560408201518160020155606082015181600301556080820151816004015590505085601c600082825461211a9190614a00565b9091555050336000908152601e60205260408120805488929061213e908490614a00565b90915550503360009081526023602052604090205473ffffffffffffffffffffffffffffffffffffffff1680156121a95773ffffffffffffffffffffffffffffffffffffffff81166000908152602080526040812080548992906121a3908490614a00565b90915550505b506121b533600061378e565b50505050505050565b606060028054141561222c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610bfe565b600280556024546301000000900460ff16156122a4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f5265776172647320636f6c6c656374696f6e20706175736564000000000000006044820152606401610bfe565b6122ae3383613c14565b600160025592915050565b60005473ffffffffffffffffffffffffffffffffffffffff163314806122f25750738412ebf45bac1b340bbe8f318b928c466c4e39ca33145b612358576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b00000000000000000000006044820152606401610bfe565b602480549115156301000000027fffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffff93151562010000027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffff95151564010000000002959095167fffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff00ffff909316929092179390931791909116179055565b73ffffffffffffffffffffffffffffffffffffffff81166000908152601e6020526040812054600454670de0b6b3a764000091610e9691614988565b600054849073ffffffffffffffffffffffffffffffffffffffff1633148061245b575061245b3382610ea0565b6124c1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f4e6f74206f776e6572206f7220746b6e206d67720000000000000000000000006044820152606401610bfe565b73ffffffffffffffffffffffffffffffffffffffff85166000908152601560205260409020546014805486929081106124fc576124fc614913565b9060005260206000200181905550826012601560008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020548154811061255d5761255d614913565b600091825260208083209190910180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff9485161790559187168152601590915260409020546013805484929081106125ce576125ce614913565b9060005260206000200160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505050505050565b73ffffffffffffffffffffffffffffffffffffffff81166000908152600e602052604090205460ff166126ac576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f496e76616c69642070726f7879000000000000000000000000000000000000006044820152606401610bfe565b73ffffffffffffffffffffffffffffffffffffffff81166000908152600f6020908152604080832033845290915290205460ff16612746576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f50726f787920686173206e6f7420616c6c6f77656420796f75207965740000006044820152606401610bfe565b33600090815260236020908152604080832080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff8616908117909155601e83528184205490845291805282208054919290916127ba908490614a00565b909155505050565b600054829073ffffffffffffffffffffffffffffffffffffffff163314806127ef57506127ef3382610ea0565b612855576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f4e6f74206f776e6572206f7220746b6e206d67720000000000000000000000006044820152606401610bfe565b5073ffffffffffffffffffffffffffffffffffffffff918216600090815260106020526040902080547fffffffffffffffffffffffff00000000000000000000000000000000000000001691909216179055565b60005473ffffffffffffffffffffffffffffffffffffffff163314806128e25750738412ebf45bac1b340bbe8f318b928c466c4e39ca33145b612948576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b00000000000000000000006044820152606401610bfe565b602480547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00811660ff90911615179055565b6002805414156129e6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610bfe565b6002805560245462010000900460ff1615612a5d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f5769746864726177616c732070617573656400000000000000000000000000006044820152606401610bfe565b610cfd338284613da0565b336000908152600e602052604090205460ff16612ae1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f496e76616c69642070726f7879000000000000000000000000000000000000006044820152606401610bfe565b336000818152600f6020908152604080832073ffffffffffffffffffffffffffffffffffffffff8681168552908352818420805460ff8116157fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00909116179055602390925290912054161415612bc05773ffffffffffffffffffffffffffffffffffffffff8116600090815260236020908152604080832080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055601e82528083205433845291805282208054919290916127ba908490614971565b50565b60245460ff610100909104161515600114612c3a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f4e6f7420696e206d6967726174696f6e000000000000000000000000000000006044820152606401610bfe565b73ffffffffffffffffffffffffffffffffffffffff8216600090815260226020908152604080832033845290915290205460ff168015612c8957503360009081526021602052604090205460ff165b612cef576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f4d69672e20696e76616c6964206f7220756e617070726f7665640000000000006044820152606401610bfe565b612cfa823383613da0565b5050565b60008060128381548110612d1457612d14614913565b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff1690508015612def57670de0b6b3a7640000601a8481548110612d5a57612d5a614913565b90600052602060002001548273ffffffffffffffffffffffffffffffffffffffff16630a3be7576040518163ffffffff1660e01b8152600401602060405180830381865afa158015612db0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612dd49190614a51565b612dde9190614988565b612de891906149c5565b9150610a96565b60148381548110612e0257612e02614913565b9060005260206000200154915050919050565b60005b601254811015612cfa57600060128281548110612e3757612e37614913565b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff1690508015612fd4578280612e895750601b8281548110612e7b57612e7b614913565b906000526020600020015442115b15612fd4576040517f6472eee100000000000000000000000000000000000000000000000000000000815230600482015242602482015273ffffffffffffffffffffffffffffffffffffffff821690636472eee1906044016020604051808303816000875af1158015612f00573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f249190614a51565b601a8381548110612f3757612f37614913565b90600052602060002001819055508073ffffffffffffffffffffffffffffffffffffffff1663513872bd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612f90573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612fb49190614a51565b601b8381548110612fc757612fc7614913565b6000918252602090912001555b5080612fdf81614a18565b915050612e18565b60005473ffffffffffffffffffffffffffffffffffffffff163314806130205750738412ebf45bac1b340bbe8f318b928c466c4e39ca33145b613086576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b00000000000000000000006044820152606401610bfe565b8051670de0b6b3a764000011156130f9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f4d757374206265203e3d204d554c2050524543000000000000000000000000006044820152606401610bfe565b6080810151600111801590613113575060a0810151600111155b613179576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f4d757374206265203e3d203100000000000000000000000000000000000000006044820152606401610bfe565b80516007556020810151600b556040810151600c556060810151600a55608081015160085560a00151600955565b6131b16000612e15565b60055442106131c4576131c261409e565b565b6131c26143d1565b60008183106131db57816131dd565b825b9392505050565b8460016131f1828261378e565b602454640100000000900460ff16158061321f57503360009081526021602052604090205460ff1615156001145b613285576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f5374616b696e6720706175736564206f7220696e206d6967726174696f6e00006044820152606401610bfe565b6009548410156132f1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f4d696e696d756d207374616b652074696d65206e6f74206d65740000000000006044820152606401610bfe565b60085484111561335d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f547279696e6720746f206c6f636b20666f7220746f6f206c6f6e6700000000006044820152606401610bfe565b60245461338b9065010000000000900473ffffffffffffffffffffffffffffffffffffffff16873088613a76565b600061339685610a9c565b73ffffffffffffffffffffffffffffffffffffffff89166000908152601e602090815260408083205490517fffffffffffffffffffffffffffffffffffffffff00000000000000000000000060608e901b169281019290925260348201889052605482018a9052607482015291925090609401604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152828252805160209182012073ffffffffffffffffffffffffffffffffffffffff8d1660009081526025835283902060a0850184528185529184018990529183018a905290925090606081016134898989614a00565b815260209081018590528254600181810185556000948552828520845160059093020191825591830151918101919091556040820151600282015560608201516003820155608090910151600490910155601c80548992906134ec908490614a00565b909155505073ffffffffffffffffffffffffffffffffffffffff89166000908152601e602052604081208054899290613526908490614a00565b909155505073ffffffffffffffffffffffffffffffffffffffff808a166000908152602360205260409020541680156135935773ffffffffffffffffffffffffffffffffffffffff81166000908152602080526040812080548a929061358d908490614a00565b90915550505b5061359f89600061378e565b604080518881526020810188905290810182905273ffffffffffffffffffffffffffffffffffffffff89811660608301528a16907ff400e72e69ef4402819dfc57eeddc66f5eb69bf405e0e8098b1946ec1ac14a229060800160405180910390a2505050505050505050565b6000613619426005546131cc565b905090565b6040805173ffffffffffffffffffffffffffffffffffffffff8481166024830152604480830185905283518084039091018152606490920183526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb0000000000000000000000000000000000000000000000000000000017905291516000928392908716916136b59190614a96565b6000604051808303816000865af19150503d80600081146136f2576040519150601f19603f3d011682016040523d82523d6000602084013e6136f7565b606091505b50915091508180156137215750805115806137215750808060200190518101906137219190614ab2565b613787576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5472616e7366657248656c7065723a205452414e534645525f4641494c4544006044820152606401610bfe565b5050505050565b801561379c5761379c6131a7565b73ffffffffffffffffffffffffffffffffffffffff821615612cfa5760008060006137c6856119ce565b9250925092506137d585614444565b73ffffffffffffffffffffffffffffffffffffffff85166000908152600d602052604090208290558281106138595760006138108483614971565b905080601d546138209190614a00565b601d5561382d8185614a00565b73ffffffffffffffffffffffffffffffffffffffff87166000908152601f602052604090205550613787565b60006138658285614971565b905080601d546138759190614971565b601d556138828185614971565b73ffffffffffffffffffffffffffffffffffffffff87166000908152601f6020526040902055505050505050565b6138e56040518060a0016040528060008019168152602001600081526020016000815260200160008152602001600081525090565b6000805b73ffffffffffffffffffffffffffffffffffffffff8516600090815260256020526040902054811015613a045773ffffffffffffffffffffffffffffffffffffffff8516600090815260256020526040902080548290811061394d5761394d614913565b9060005260206000209060050201600001548414156139f25773ffffffffffffffffffffffffffffffffffffffff8516600090815260256020526040902080548290811061399d5761399d614913565b90600052602060002090600502016040518060a0016040529081600082015481526020016001820154815260200160028201548152602001600382015481526020016004820154815250509250809150613a04565b806139fc81614a18565b9150506138e9565b5081518314613a6f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f5374616b65206e6f7420666f756e6400000000000000000000000000000000006044820152606401610bfe565b9250929050565b6040805173ffffffffffffffffffffffffffffffffffffffff85811660248301528481166044830152606480830185905283518084039091018152608490920183526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f23b872dd000000000000000000000000000000000000000000000000000000001790529151600092839290881691613b159190614a96565b6000604051808303816000865af19150503d8060008114613b52576040519150601f19603f3d011682016040523d82523d6000602084013e613b57565b606091505b5091509150818015613b81575080511580613b81575080806020019051810190613b819190614ab2565b613c0c576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f5472616e7366657248656c7065723a205452414e534645525f46524f4d5f464160448201527f494c4544000000000000000000000000000000000000000000000000000000006064820152608401610bfe565b505050505050565b6060826001613c23828261378e565b60115467ffffffffffffffff811115613c3e57613c3e61483f565b604051908082528060200260200182016040528015613c67578160200160208202803683370190505b50925060005b601154811015613d705773ffffffffffffffffffffffffffffffffffffffff861660009081526018602090815260408083208484529091529020548451859083908110613cbc57613cbc614913565b60209081029190910181019190915273ffffffffffffffffffffffffffffffffffffffff871660009081526018825260408082208483529092529081205560118054613d5e919083908110613d1357613d13614913565b9060005260206000200160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1686868481518110613d5157613d51614913565b602002602001015161361e565b80613d6881614a18565b915050613c6d565b50505073ffffffffffffffffffffffffffffffffffffffff90921660009081526019602052604090204290555090565b613daa8383613c14565b50600080613db885846138b0565b91509150816060015142101580613dd6575060245460ff1615156001145b80613df557503360009081526021602052604090205460ff1615156001145b613e5b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f5374616b65206973207374696c6c206c6f636b656421000000000000000000006044820152606401610bfe565b60408201518015613c0c5780601c54613e749190614971565b601c5573ffffffffffffffffffffffffffffffffffffffff86166000908152601e6020526040902054613ea8908290614971565b73ffffffffffffffffffffffffffffffffffffffff8088166000908152601e6020908152604080832094909455602390529190912054168015613f1f5773ffffffffffffffffffffffffffffffffffffffff8116600090815260208052604081208054849290613f19908490614971565b90915550505b5073ffffffffffffffffffffffffffffffffffffffff86166000908152602560205260409020805483908110613f5757613f57614913565b60009182526020822060059190910201818155600181018290556002810182905560038101829055600490810191909155602480546040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff898116948201949094529182018490526501000000000090049091169063a9059cbb906044016020604051808303816000875af115801561400c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906140309190614ab2565b5061403c86600061378e565b604080518281526020810186905273ffffffffffffffffffffffffffffffffffffffff878116828401529151918816917f1d9308f6b22a2754a1c622bb30889e8f8f956c83e524d039e9d65d5f052eb9089181900360600190a2505050505050565b60005b60135481101561418f576000601382815481106140c0576140c0614913565b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff169050801561417c576040517f092193ab00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff82169063092193ab9060240160408051808303816000875af1158015614155573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906141799190614acf565b50505b508061418781614a18565b9150506140a1565b50600062093a80600554426141a49190614971565b6141ae91906149c5565b905060005b60115481101561439157601181815481106141d0576141d0614913565b6000918252602090912001546040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff909116906370a0823190602401602060405180830381865afa158015614247573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061426b9190614a51565b614276836001614a00565b62093a8061428384612cfe565b61428d9190614988565b6142979190614988565b1115601182815481106142ac576142ac614913565b60009182526020918290200154604080517f4e6f7420656e6f7567682072657761726420746f6b656e7320617661696c6162938101939093527f6c653a20000000000000000000000000000000000000000000000000000000009083015260601b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000001660448201526058016040516020818303038152906040529061437e576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610bfe9190614af3565b508061438981614a18565b9150506141b3565b5062093a806143a1826001614a00565b6143ab9190614988565b6005546143b89190614a00565b6005556143c36143d1565b6143cb611447565b60045550565b60006143db6114db565b905060005b601654811015614435578181815181106143fc576143fc614913565b60200260200101516016828154811061441757614417614913565b6000918252602090912001558061442d81614a18565b9150506143e0565b5061443e61360b565b60065550565b73ffffffffffffffffffffffffffffffffffffffff811615612bc057600061446b8261091d565b905060005b81518110156144d95781818151811061448b5761448b614913565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff851660009081526018835260408082208583529093529190912055806144d181614a18565b915050614470565b5060005b81518110156119c957601681815481106144f9576144f9614913565b600091825260208083209091015473ffffffffffffffffffffffffffffffffffffffff861683526017825260408084208585529092529120558061453c81614a18565b9150506144dd565b803573ffffffffffffffffffffffffffffffffffffffff8116811461456857600080fd5b919050565b60006020828403121561457f57600080fd5b6131dd82614544565b6020808252825182820181905260009190848201906040850190845b818110156145c0578351835292840192918401916001016145a4565b50909695505050505050565b6000602082840312156145de57600080fd5b5035919050565b6020808252825182820181905260009190848201906040850190845b818110156145c057835173ffffffffffffffffffffffffffffffffffffffff1683529284019291840191600101614601565b6000806040838503121561464657600080fd5b50508035926020909101359150565b602080825282518282018190526000919060409081850190868401855b828110156146b65781518051855286810151878601528581015186860152606080820151908601526080908101519085015260a09093019290850190600101614672565b5091979650505050505050565b600080604083850312156146d657600080fd5b6146df83614544565b91506146ed60208401614544565b90509250929050565b6000806000806080858703121561470c57600080fd5b61471585614544565b966020860135965060408601359560600135945092505050565b6000806040838503121561474257600080fd5b61474b83614544565b946020939093013593505050565b8015158114612bc057600080fd5b60008060006060848603121561477c57600080fd5b833561478781614759565b9250602084013561479781614759565b915060408401356147a781614759565b809150509250925092565b600080600080608085870312156147c857600080fd5b6147d185614544565b9350602085013592506147e660408601614544565b91506147f460608601614544565b905092959194509250565b6000806040838503121561481257600080fd5b823591506146ed60208401614544565b60006020828403121561483457600080fd5b81356131dd81614759565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600060c0828403121561488057600080fd5b82601f83011261488f57600080fd5b60405160c0810181811067ffffffffffffffff821117156148d9577f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040528060c08401858111156148ee57600080fd5b845b818110156149085780358352602092830192016148f0565b509195945050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60008282101561498357614983614942565b500390565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04831182151516156149c0576149c0614942565b500290565b6000826149fb577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b60008219821115614a1357614a13614942565b500190565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff821415614a4a57614a4a614942565b5060010190565b600060208284031215614a6357600080fd5b5051919050565b60005b83811015614a85578181015183820152602001614a6d565b838111156110485750506000910152565b60008251614aa8818460208701614a6a565b9190910192915050565b600060208284031215614ac457600080fd5b81516131dd81614759565b60008060408385031215614ae257600080fd5b505080516020909101519092909150565b6020815260008251806020840152614b12816040850160208701614a6a565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016919091016040019291505056fea26469706673582212205efa6d08b2eb70ca21abb4b800afe279cbd5aa94eedb9e5c5b96bc1201312def64736f6c634300080a0033000000000000000000000000ff5b4bcbf765fe363269114e1c765229a29edefd00000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000001a000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000260000000000000000000000000c14900dfb1aa54e7674e1ecf9ce02b3b35157ba500000000000000000000000000000000000000000000000000000000000000020000000000000000000000003432b6a60d23ca0dfca7761b7ab56459d9c964d00000000000000000000000001b40183efb4dd766f11bda7a7c3ad8982e9984210000000000000000000000000000000000000000000000000000000000000002000000000000000000000000b1748c79709f4ba2dd82834b8c82d4a505003f270000000000000000000000009520b477aa81180e6ddc006fc09fb6d3eb4e807a000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000a86cc92e3da00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000278dc748eda1d8efef1adfb518542612b49fcd340000000000000000000000000000000000000000000000000000000000000000
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106103ae5760003560e01c80638da5cb5b116101f4578063d5e1a9c61161011a578063eb3c209e116100ad578063f2caeb1e1161007c578063f2caeb1e146108dc578063f77e34d1146108ef578063facefb6414610902578063fff6cae91461091557600080fd5b8063eb3c209e146108ae578063ebe2b12b146108c1578063f288baf6146108ca578063f2a8d349146108d357600080fd5b8063e01f62bf116100e9578063e01f62bf14610878578063e1ba95d214610880578063e44b9fa514610888578063e7f305821461089b57600080fd5b8063d5e1a9c614610809578063d7400d561461081c578063d9f96e8d1461082f578063de1a65511461086557600080fd5b8063b85efd0611610192578063ca6df29d11610161578063ca6df29d146107a4578063cc2abd64146107da578063cdc82e80146107ed578063d42fc9b4146107f657600080fd5b8063b85efd061461076c578063b94c4dcb1461077f578063c00007b014610788578063c8f33c911461079b57600080fd5b8063a0f23476116101ce578063a0f2347614610735578063a2217bc514610748578063aa1d4fce14610750578063affaa7a41461075957600080fd5b80638da5cb5b146106f557806391cf600a146107155780639637927f1461072857600080fd5b806341a16f3f116102d957806370641a36116102775780637d6ef08e116102465780637d6ef08e146106825780637f472e54146106a15780638980f11f146106b45780638bad86a7146106c757600080fd5b806370641a361461060e57806372f702f3146106165780637970833e1461063f57806379ba50971461067a57600080fd5b80635bfd9258116102b35780635bfd9258146105d557806364f2c060146105dd57806369339245146105e55780636e27cef91461060557600080fd5b806341a16f3f1461056c5780634fd2b536146105a257806353a47bb7146105b557600080fd5b80631face856116103515780632c0c2a0a116103205780632c0c2a0a146105065780633650aff21461051957806336f89af21461052c578063386a95251461056257600080fd5b80631face85614610462578063231b68dc1461047557806328408bab1461049857806328ef934e146104f357600080fd5b80631627540c1161038d5780631627540c1461041257806317b18c89146104275780631c1f78eb1461043a5780631e090f011461044257600080fd5b80628cc262146103b35780630d7bac4f146103dc57806312edb24c146103fd575b600080fd5b6103c66103c136600461456d565b61091d565b6040516103d39190614588565b60405180910390f35b6103ef6103ea3660046145cc565b610a9c565b6040519081526020016103d3565b610405610aec565b6040516103d391906145e5565b61042561042036600461456d565b610b5b565b005b610425610435366004614633565b610c80565b6103c6610d06565b61045561045036600461456d565b610da7565b6040516103d39190614655565b6103ef61047036600461456d565b610e5b565b6104886104833660046146c3565b610ea0565b60405190151581526020016103d3565b6104ce6104a636600461456d565b60236020526000908152604090205473ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016103d3565b6104256105013660046146f6565b610f0f565b6103ef61051436600461456d565b61104e565b61042561052736600461456d565b611333565b6103ef61053a36600461456d565b73ffffffffffffffffffffffffffffffffffffffff166000908152601f602052604090205490565b6103ef62093a8081565b6104ce61057a36600461456d565b60106020526000908152604090205473ffffffffffffffffffffffffffffffffffffffff1681565b6103ef6105b036600461456d565b611426565b6001546104ce9073ffffffffffffffffffffffffffffffffffffffff1681565b6103ef611447565b601d546103ef565b6103ef6105f336600461456d565b60156020526000908152604090205481565b6103ef60095481565b6103c66114db565b6024546104ce9065010000000000900473ffffffffffffffffffffffffffffffffffffffff1681565b61065261064d36600461472f565b61163a565b604080519586526020860194909452928401919091526060830152608082015260a0016103d3565b610425611688565b6103ef61069036600461456d565b602080526000908152604090205481565b6103ef6106af36600461456d565b6117d3565b6104256106c236600461472f565b6117ea565b6106da6106d536600461456d565b6119ce565b604080519384526020840192909252908201526060016103d3565b6000546104ce9073ffffffffffffffffffffffffffffffffffffffff1681565b61042561072336600461456d565b611c9c565b6024546104889060ff1681565b6103ef61074336600461456d565b611d8f565b610425611e4a565b6103ef600a5481565b61042561076736600461456d565b611f23565b61042561077a366004614633565b612013565b6103ef60085481565b6103c661079636600461456d565b6121be565b6103ef60065481565b6103ef6107b236600461456d565b73ffffffffffffffffffffffffffffffffffffffff1660009081526025602052604090205490565b6104256107e8366004614767565b6122b9565b6103ef60075481565b6103ef61080436600461456d565b6123f2565b6104256108173660046147b2565b61242e565b61042561082a36600461456d565b61261d565b6103ef61083d36600461456d565b73ffffffffffffffffffffffffffffffffffffffff166000908152601e602052604090205490565b6104256108733660046146c3565b6127c2565b601c546103ef565b6104256128a9565b6104256108963660046147ff565b61297a565b6104256108a936600461456d565b612a68565b6104256108bc36600461472f565b612bc3565b6103ef60055481565b6103ef600b5481565b6103ef600c5481565b6103ef6108ea3660046145cc565b612cfe565b6104256108fd366004614822565b612e15565b61042561091036600461486e565b612fe7565b6104256131a7565b606060006109296114db565b60115490915067ffffffffffffffff8111156109475761094761483f565b604051908082528060200260200182016040528015610970578160200160208202803683370190505b5073ffffffffffffffffffffffffffffffffffffffff84166000908152601f602052604090205490925015610a965760005b601154811015610a945773ffffffffffffffffffffffffffffffffffffffff84166000818152601860209081526040808320858452825280832054938352601782528083208584529091529020548351670de0b6b3a76400009190859085908110610a0f57610a0f614913565b6020026020010151610a219190614971565b73ffffffffffffffffffffffffffffffffffffffff87166000908152601f6020526040902054610a519190614988565b610a5b91906149c5565b610a659190614a00565b838281518110610a7757610a77614913565b602090810291909101015280610a8c81614a18565b9150506109a2565b505b50919050565b600754600854600091610ae691610abb670de0b6b3a764000083614971565b610ac59086614988565b610acf91906149c5565b610ae190670de0b6b3a7640000614a00565b6131cc565b92915050565b60606011805480602002602001604051908101604052809291908181526020018280548015610b5157602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff168152600190910190602001808311610b26575b5050505050905090565b60005473ffffffffffffffffffffffffffffffffffffffff163314610c07576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602f60248201527f4f6e6c792074686520636f6e7472616374206f776e6572206d6179207065726660448201527f6f726d207468697320616374696f6e000000000000000000000000000000000060648201526084015b60405180910390fd5b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040519081527f906a1c6bd7e3091ea86693dd029a831c19049ce77f1dce2ce0bab1cacbabce229060200160405180910390a150565b600280541415610cec576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610bfe565b60028055610cfd33808484426131e4565b50506001600255565b60145460609067ffffffffffffffff811115610d2457610d2461483f565b604051908082528060200260200182016040528015610d4d578160200160208202803683370190505b50905060005b601454811015610da35762093a80610d6a82612cfe565b610d749190614988565b828281518110610d8657610d86614913565b602090810291909101015280610d9b81614a18565b915050610d53565b5090565b73ffffffffffffffffffffffffffffffffffffffff81166000908152602560209081526040808320805482518185028101850190935280835260609492939192909184015b82821015610e5057838290600052602060002090600502016040518060a00160405290816000820154815260200160018201548152602001600282015481526020016003820154815260200160048201548152505081526020019060010190610dec565b505050509050919050565b73ffffffffffffffffffffffffffffffffffffffff81166000908152602080526040812054600454670de0b6b3a764000091610e9691614988565b610ae691906149c5565b6000805473ffffffffffffffffffffffffffffffffffffffff84811691161415610ecc57506001610ae6565b73ffffffffffffffffffffffffffffffffffffffff82811660009081526010602052604090205481169084161415610f0657506001610ae6565b50600092915050565b60245460ff610100909104161515600114610f86576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f4e6f7420696e206d6967726174696f6e000000000000000000000000000000006044820152606401610bfe565b73ffffffffffffffffffffffffffffffffffffffff8416600090815260226020908152604080832033845290915290205460ff168015610fd557503360009081526021602052604090205460ff165b61103b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f4d69672e20696e76616c6964206f7220756e617070726f7665640000000000006044820152606401610bfe565b61104884338585856131e4565b50505050565b73ffffffffffffffffffffffffffffffffffffffff80821660009081526023602052604081205490918291168015611119576003546040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8381166004830152909116906370a0823190602401602060405180830381865afa1580156110f0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111149190614a51565b6111ad565b6003546040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8681166004830152909116906370a0823190602401602060405180830381865afa158015611189573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111ad9190614a51565b91506000670de0b6b3a7640000600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611227573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061124b9190614a51565b6112559190614988565b600a54600b546112659086614988565b61126f9190614988565b61127991906149c5565b905060008073ffffffffffffffffffffffffffffffffffffffff8416156112a8576112a3846117d3565b6112b1565b6112b187611426565b90508015611303576000816112ce670de0b6b3a764000088614988565b6112d891906149c5565b9050670de0b6b3a7640000600b54826112f19190614988565b6112fb91906149c5565b925050611308565b600091505b508082116113165780611318565b815b9450600b5485111561132a57600b5494505b50505050919050565b60005473ffffffffffffffffffffffffffffffffffffffff1633148061136c5750738412ebf45bac1b340bbe8f318b928c466c4e39ca33145b6113d2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b00000000000000000000006044820152606401610bfe565b73ffffffffffffffffffffffffffffffffffffffff16600090815260216020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00811660ff90911615179055565b6000670de0b6b3a7640000600c5461143d846123f2565b610e969190614988565b600080602460059054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166399530b066040518163ffffffff1660e01b8152600401602060405180830381865afa1580156114b7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ae69190614a51565b6060601c54600014806114ee5750601d54155b15611548576016805480602002602001604051908101604052809291908181526020018280548015610b5157602002820191906000526020600020905b81548152602001906001019080831161152b575050505050905090565b60115467ffffffffffffffff8111156115635761156361483f565b60405190808252806020026020018201604052801561158c578160200160208202803683370190505b50905060005b601654811015610da357601d546115a882612cfe565b6006546115b361360b565b6115bd9190614971565b6115c79190614988565b6115d990670de0b6b3a7640000614988565b6115e391906149c5565b601682815481106115f6576115f6614913565b906000526020600020015461160b9190614a00565b82828151811061161d5761161d614913565b60209081029190910101528061163281614a18565b915050611592565b6025602052816000526040600020818154811061165657600080fd5b600091825260209091206005909102018054600182015460028301546003840154600490940154929550909350919085565b60015473ffffffffffffffffffffffffffffffffffffffff16331461172f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603560248201527f596f75206d757374206265206e6f6d696e61746564206265666f726520796f7560448201527f2063616e20616363657074206f776e65727368697000000000000000000000006064820152608401610bfe565b6000546001546040805173ffffffffffffffffffffffffffffffffffffffff93841681529290911660208301527fb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159c910160405180910390a160018054600080547fffffffffffffffffffffffff000000000000000000000000000000000000000090811673ffffffffffffffffffffffffffffffffffffffff841617909155169055565b6000670de0b6b3a7640000600c5461143d84610e5b565b600054829073ffffffffffffffffffffffffffffffffffffffff1633148061181757506118173382610ea0565b61187d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f4e6f74206f776e6572206f7220746b6e206d67720000000000000000000000006044820152606401610bfe565b6000805b6011548110156118f8578473ffffffffffffffffffffffffffffffffffffffff16601182815481106118b5576118b5614913565b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff1614156118e657600191506118f8565b806118f081614a18565b915050611881565b5080801561192c575073ffffffffffffffffffffffffffffffffffffffff8481166000908152601060205260409020541633145b80611957575080158015611957575060005473ffffffffffffffffffffffffffffffffffffffff1633145b156119675761104884338561361e565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f4e6f2076616c696420746f6b656e7320746f207265636f7665720000000000006044820152606401610bfe565b505050565b73ffffffffffffffffffffffffffffffffffffffff81166000908152601f602052604081205490806119ff8461104e565b73ffffffffffffffffffffffffffffffffffffffff85166000908152601e602052604081205491935090158015611a59575073ffffffffffffffffffffffffffffffffffffffff85166000908152601f6020526040902054155b15611a65575081611aa5565b73ffffffffffffffffffffffffffffffffffffffff85166000908152600d6020526040902054600290611a989085614a00565b611aa291906149c5565b90505b6000915060005b73ffffffffffffffffffffffffffffffffffffffff8616600090815260256020526040902054811015611c935773ffffffffffffffffffffffffffffffffffffffff86166000908152602560205260408120805483908110611b1057611b10614913565b90600052602060002090600502016040518060a001604052908160008201548152602001600182015481526020016002820154815260200160038201548152602001600482015481525050905060008160800151905042826060015111611c4057606082015173ffffffffffffffffffffffffffffffffffffffff89166000908152601960205260409020541015611c355773ffffffffffffffffffffffffffffffffffffffff88166000908152601960205260408120546060840151611bd79190614971565b90506000836060015142611beb9190614971565b90506000611c0182670de0b6b3a7640000614988565b611c0b8486614988565b611c159190614a00565b9050611c218284614a00565b611c2b90826149c5565b9350505050611c40565b50670de0b6b3a76400005b60408201516000670de0b6b3a7640000611c5a8785614a00565b611c649084614988565b611c6e91906149c5565b9050611c7a8188614a00565b9650505050508080611c8b90614a18565b915050611aac565b50509193909250565b60005473ffffffffffffffffffffffffffffffffffffffff16331480611cd55750738412ebf45bac1b340bbe8f318b928c466c4e39ca33145b611d3b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b00000000000000000000006044820152606401610bfe565b73ffffffffffffffffffffffffffffffffffffffff166000908152600e6020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00811660ff90911615179055565b6000600454600c54611da19190614988565b6003546040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8581166004830152670de0b6b3a76400009283929116906370a0823190602401602060405180830381865afa158015611e1c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e409190614a51565b61143d9190614988565b60005473ffffffffffffffffffffffffffffffffffffffff16331480611e835750738412ebf45bac1b340bbe8f318b928c466c4e39ca33145b611ee9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b00000000000000000000006044820152606401610bfe565b602480547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff81166101009182900460ff1615909102179055565b73ffffffffffffffffffffffffffffffffffffffff811660009081526021602052604090205460ff16611fb2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f496e76616c6964206d69677261746f72206164647265737300000000000000006044820152606401610bfe565b33600090815260226020908152604080832073ffffffffffffffffffffffffffffffffffffffff94909416835292905220805460ff8116157fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00909116179055565b336001612020828261378e565b60008061202d33876138b0565b9150915060008583604001516120439190614a00565b90506024546120739065010000000000900473ffffffffffffffffffffffffffffffffffffffff16333089613a76565b6040805160a0810182528881526020858101518183015281830184905260608087015190830152608080870151908301523360009081526025909152919091208054849081106120c5576120c5614913565b9060005260206000209060050201600082015181600001556020820151816001015560408201518160020155606082015181600301556080820151816004015590505085601c600082825461211a9190614a00565b9091555050336000908152601e60205260408120805488929061213e908490614a00565b90915550503360009081526023602052604090205473ffffffffffffffffffffffffffffffffffffffff1680156121a95773ffffffffffffffffffffffffffffffffffffffff81166000908152602080526040812080548992906121a3908490614a00565b90915550505b506121b533600061378e565b50505050505050565b606060028054141561222c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610bfe565b600280556024546301000000900460ff16156122a4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f5265776172647320636f6c6c656374696f6e20706175736564000000000000006044820152606401610bfe565b6122ae3383613c14565b600160025592915050565b60005473ffffffffffffffffffffffffffffffffffffffff163314806122f25750738412ebf45bac1b340bbe8f318b928c466c4e39ca33145b612358576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b00000000000000000000006044820152606401610bfe565b602480549115156301000000027fffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffff93151562010000027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffff95151564010000000002959095167fffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff00ffff909316929092179390931791909116179055565b73ffffffffffffffffffffffffffffffffffffffff81166000908152601e6020526040812054600454670de0b6b3a764000091610e9691614988565b600054849073ffffffffffffffffffffffffffffffffffffffff1633148061245b575061245b3382610ea0565b6124c1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f4e6f74206f776e6572206f7220746b6e206d67720000000000000000000000006044820152606401610bfe565b73ffffffffffffffffffffffffffffffffffffffff85166000908152601560205260409020546014805486929081106124fc576124fc614913565b9060005260206000200181905550826012601560008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020548154811061255d5761255d614913565b600091825260208083209190910180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff9485161790559187168152601590915260409020546013805484929081106125ce576125ce614913565b9060005260206000200160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505050505050565b73ffffffffffffffffffffffffffffffffffffffff81166000908152600e602052604090205460ff166126ac576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f496e76616c69642070726f7879000000000000000000000000000000000000006044820152606401610bfe565b73ffffffffffffffffffffffffffffffffffffffff81166000908152600f6020908152604080832033845290915290205460ff16612746576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f50726f787920686173206e6f7420616c6c6f77656420796f75207965740000006044820152606401610bfe565b33600090815260236020908152604080832080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff8616908117909155601e83528184205490845291805282208054919290916127ba908490614a00565b909155505050565b600054829073ffffffffffffffffffffffffffffffffffffffff163314806127ef57506127ef3382610ea0565b612855576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f4e6f74206f776e6572206f7220746b6e206d67720000000000000000000000006044820152606401610bfe565b5073ffffffffffffffffffffffffffffffffffffffff918216600090815260106020526040902080547fffffffffffffffffffffffff00000000000000000000000000000000000000001691909216179055565b60005473ffffffffffffffffffffffffffffffffffffffff163314806128e25750738412ebf45bac1b340bbe8f318b928c466c4e39ca33145b612948576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b00000000000000000000006044820152606401610bfe565b602480547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00811660ff90911615179055565b6002805414156129e6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610bfe565b6002805560245462010000900460ff1615612a5d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f5769746864726177616c732070617573656400000000000000000000000000006044820152606401610bfe565b610cfd338284613da0565b336000908152600e602052604090205460ff16612ae1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f496e76616c69642070726f7879000000000000000000000000000000000000006044820152606401610bfe565b336000818152600f6020908152604080832073ffffffffffffffffffffffffffffffffffffffff8681168552908352818420805460ff8116157fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00909116179055602390925290912054161415612bc05773ffffffffffffffffffffffffffffffffffffffff8116600090815260236020908152604080832080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055601e82528083205433845291805282208054919290916127ba908490614971565b50565b60245460ff610100909104161515600114612c3a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f4e6f7420696e206d6967726174696f6e000000000000000000000000000000006044820152606401610bfe565b73ffffffffffffffffffffffffffffffffffffffff8216600090815260226020908152604080832033845290915290205460ff168015612c8957503360009081526021602052604090205460ff165b612cef576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f4d69672e20696e76616c6964206f7220756e617070726f7665640000000000006044820152606401610bfe565b612cfa823383613da0565b5050565b60008060128381548110612d1457612d14614913565b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff1690508015612def57670de0b6b3a7640000601a8481548110612d5a57612d5a614913565b90600052602060002001548273ffffffffffffffffffffffffffffffffffffffff16630a3be7576040518163ffffffff1660e01b8152600401602060405180830381865afa158015612db0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612dd49190614a51565b612dde9190614988565b612de891906149c5565b9150610a96565b60148381548110612e0257612e02614913565b9060005260206000200154915050919050565b60005b601254811015612cfa57600060128281548110612e3757612e37614913565b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff1690508015612fd4578280612e895750601b8281548110612e7b57612e7b614913565b906000526020600020015442115b15612fd4576040517f6472eee100000000000000000000000000000000000000000000000000000000815230600482015242602482015273ffffffffffffffffffffffffffffffffffffffff821690636472eee1906044016020604051808303816000875af1158015612f00573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f249190614a51565b601a8381548110612f3757612f37614913565b90600052602060002001819055508073ffffffffffffffffffffffffffffffffffffffff1663513872bd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612f90573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612fb49190614a51565b601b8381548110612fc757612fc7614913565b6000918252602090912001555b5080612fdf81614a18565b915050612e18565b60005473ffffffffffffffffffffffffffffffffffffffff163314806130205750738412ebf45bac1b340bbe8f318b928c466c4e39ca33145b613086576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b00000000000000000000006044820152606401610bfe565b8051670de0b6b3a764000011156130f9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f4d757374206265203e3d204d554c2050524543000000000000000000000000006044820152606401610bfe565b6080810151600111801590613113575060a0810151600111155b613179576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f4d757374206265203e3d203100000000000000000000000000000000000000006044820152606401610bfe565b80516007556020810151600b556040810151600c556060810151600a55608081015160085560a00151600955565b6131b16000612e15565b60055442106131c4576131c261409e565b565b6131c26143d1565b60008183106131db57816131dd565b825b9392505050565b8460016131f1828261378e565b602454640100000000900460ff16158061321f57503360009081526021602052604090205460ff1615156001145b613285576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f5374616b696e6720706175736564206f7220696e206d6967726174696f6e00006044820152606401610bfe565b6009548410156132f1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f4d696e696d756d207374616b652074696d65206e6f74206d65740000000000006044820152606401610bfe565b60085484111561335d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f547279696e6720746f206c6f636b20666f7220746f6f206c6f6e6700000000006044820152606401610bfe565b60245461338b9065010000000000900473ffffffffffffffffffffffffffffffffffffffff16873088613a76565b600061339685610a9c565b73ffffffffffffffffffffffffffffffffffffffff89166000908152601e602090815260408083205490517fffffffffffffffffffffffffffffffffffffffff00000000000000000000000060608e901b169281019290925260348201889052605482018a9052607482015291925090609401604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152828252805160209182012073ffffffffffffffffffffffffffffffffffffffff8d1660009081526025835283902060a0850184528185529184018990529183018a905290925090606081016134898989614a00565b815260209081018590528254600181810185556000948552828520845160059093020191825591830151918101919091556040820151600282015560608201516003820155608090910151600490910155601c80548992906134ec908490614a00565b909155505073ffffffffffffffffffffffffffffffffffffffff89166000908152601e602052604081208054899290613526908490614a00565b909155505073ffffffffffffffffffffffffffffffffffffffff808a166000908152602360205260409020541680156135935773ffffffffffffffffffffffffffffffffffffffff81166000908152602080526040812080548a929061358d908490614a00565b90915550505b5061359f89600061378e565b604080518881526020810188905290810182905273ffffffffffffffffffffffffffffffffffffffff89811660608301528a16907ff400e72e69ef4402819dfc57eeddc66f5eb69bf405e0e8098b1946ec1ac14a229060800160405180910390a2505050505050505050565b6000613619426005546131cc565b905090565b6040805173ffffffffffffffffffffffffffffffffffffffff8481166024830152604480830185905283518084039091018152606490920183526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb0000000000000000000000000000000000000000000000000000000017905291516000928392908716916136b59190614a96565b6000604051808303816000865af19150503d80600081146136f2576040519150601f19603f3d011682016040523d82523d6000602084013e6136f7565b606091505b50915091508180156137215750805115806137215750808060200190518101906137219190614ab2565b613787576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5472616e7366657248656c7065723a205452414e534645525f4641494c4544006044820152606401610bfe565b5050505050565b801561379c5761379c6131a7565b73ffffffffffffffffffffffffffffffffffffffff821615612cfa5760008060006137c6856119ce565b9250925092506137d585614444565b73ffffffffffffffffffffffffffffffffffffffff85166000908152600d602052604090208290558281106138595760006138108483614971565b905080601d546138209190614a00565b601d5561382d8185614a00565b73ffffffffffffffffffffffffffffffffffffffff87166000908152601f602052604090205550613787565b60006138658285614971565b905080601d546138759190614971565b601d556138828185614971565b73ffffffffffffffffffffffffffffffffffffffff87166000908152601f6020526040902055505050505050565b6138e56040518060a0016040528060008019168152602001600081526020016000815260200160008152602001600081525090565b6000805b73ffffffffffffffffffffffffffffffffffffffff8516600090815260256020526040902054811015613a045773ffffffffffffffffffffffffffffffffffffffff8516600090815260256020526040902080548290811061394d5761394d614913565b9060005260206000209060050201600001548414156139f25773ffffffffffffffffffffffffffffffffffffffff8516600090815260256020526040902080548290811061399d5761399d614913565b90600052602060002090600502016040518060a0016040529081600082015481526020016001820154815260200160028201548152602001600382015481526020016004820154815250509250809150613a04565b806139fc81614a18565b9150506138e9565b5081518314613a6f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f5374616b65206e6f7420666f756e6400000000000000000000000000000000006044820152606401610bfe565b9250929050565b6040805173ffffffffffffffffffffffffffffffffffffffff85811660248301528481166044830152606480830185905283518084039091018152608490920183526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f23b872dd000000000000000000000000000000000000000000000000000000001790529151600092839290881691613b159190614a96565b6000604051808303816000865af19150503d8060008114613b52576040519150601f19603f3d011682016040523d82523d6000602084013e613b57565b606091505b5091509150818015613b81575080511580613b81575080806020019051810190613b819190614ab2565b613c0c576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f5472616e7366657248656c7065723a205452414e534645525f46524f4d5f464160448201527f494c4544000000000000000000000000000000000000000000000000000000006064820152608401610bfe565b505050505050565b6060826001613c23828261378e565b60115467ffffffffffffffff811115613c3e57613c3e61483f565b604051908082528060200260200182016040528015613c67578160200160208202803683370190505b50925060005b601154811015613d705773ffffffffffffffffffffffffffffffffffffffff861660009081526018602090815260408083208484529091529020548451859083908110613cbc57613cbc614913565b60209081029190910181019190915273ffffffffffffffffffffffffffffffffffffffff871660009081526018825260408082208483529092529081205560118054613d5e919083908110613d1357613d13614913565b9060005260206000200160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1686868481518110613d5157613d51614913565b602002602001015161361e565b80613d6881614a18565b915050613c6d565b50505073ffffffffffffffffffffffffffffffffffffffff90921660009081526019602052604090204290555090565b613daa8383613c14565b50600080613db885846138b0565b91509150816060015142101580613dd6575060245460ff1615156001145b80613df557503360009081526021602052604090205460ff1615156001145b613e5b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f5374616b65206973207374696c6c206c6f636b656421000000000000000000006044820152606401610bfe565b60408201518015613c0c5780601c54613e749190614971565b601c5573ffffffffffffffffffffffffffffffffffffffff86166000908152601e6020526040902054613ea8908290614971565b73ffffffffffffffffffffffffffffffffffffffff8088166000908152601e6020908152604080832094909455602390529190912054168015613f1f5773ffffffffffffffffffffffffffffffffffffffff8116600090815260208052604081208054849290613f19908490614971565b90915550505b5073ffffffffffffffffffffffffffffffffffffffff86166000908152602560205260409020805483908110613f5757613f57614913565b60009182526020822060059190910201818155600181018290556002810182905560038101829055600490810191909155602480546040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff898116948201949094529182018490526501000000000090049091169063a9059cbb906044016020604051808303816000875af115801561400c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906140309190614ab2565b5061403c86600061378e565b604080518281526020810186905273ffffffffffffffffffffffffffffffffffffffff878116828401529151918816917f1d9308f6b22a2754a1c622bb30889e8f8f956c83e524d039e9d65d5f052eb9089181900360600190a2505050505050565b60005b60135481101561418f576000601382815481106140c0576140c0614913565b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff169050801561417c576040517f092193ab00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff82169063092193ab9060240160408051808303816000875af1158015614155573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906141799190614acf565b50505b508061418781614a18565b9150506140a1565b50600062093a80600554426141a49190614971565b6141ae91906149c5565b905060005b60115481101561439157601181815481106141d0576141d0614913565b6000918252602090912001546040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff909116906370a0823190602401602060405180830381865afa158015614247573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061426b9190614a51565b614276836001614a00565b62093a8061428384612cfe565b61428d9190614988565b6142979190614988565b1115601182815481106142ac576142ac614913565b60009182526020918290200154604080517f4e6f7420656e6f7567682072657761726420746f6b656e7320617661696c6162938101939093527f6c653a20000000000000000000000000000000000000000000000000000000009083015260601b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000001660448201526058016040516020818303038152906040529061437e576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610bfe9190614af3565b508061438981614a18565b9150506141b3565b5062093a806143a1826001614a00565b6143ab9190614988565b6005546143b89190614a00565b6005556143c36143d1565b6143cb611447565b60045550565b60006143db6114db565b905060005b601654811015614435578181815181106143fc576143fc614913565b60200260200101516016828154811061441757614417614913565b6000918252602090912001558061442d81614a18565b9150506143e0565b5061443e61360b565b60065550565b73ffffffffffffffffffffffffffffffffffffffff811615612bc057600061446b8261091d565b905060005b81518110156144d95781818151811061448b5761448b614913565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff851660009081526018835260408082208583529093529190912055806144d181614a18565b915050614470565b5060005b81518110156119c957601681815481106144f9576144f9614913565b600091825260208083209091015473ffffffffffffffffffffffffffffffffffffffff861683526017825260408084208585529092529120558061453c81614a18565b9150506144dd565b803573ffffffffffffffffffffffffffffffffffffffff8116811461456857600080fd5b919050565b60006020828403121561457f57600080fd5b6131dd82614544565b6020808252825182820181905260009190848201906040850190845b818110156145c0578351835292840192918401916001016145a4565b50909695505050505050565b6000602082840312156145de57600080fd5b5035919050565b6020808252825182820181905260009190848201906040850190845b818110156145c057835173ffffffffffffffffffffffffffffffffffffffff1683529284019291840191600101614601565b6000806040838503121561464657600080fd5b50508035926020909101359150565b602080825282518282018190526000919060409081850190868401855b828110156146b65781518051855286810151878601528581015186860152606080820151908601526080908101519085015260a09093019290850190600101614672565b5091979650505050505050565b600080604083850312156146d657600080fd5b6146df83614544565b91506146ed60208401614544565b90509250929050565b6000806000806080858703121561470c57600080fd5b61471585614544565b966020860135965060408601359560600135945092505050565b6000806040838503121561474257600080fd5b61474b83614544565b946020939093013593505050565b8015158114612bc057600080fd5b60008060006060848603121561477c57600080fd5b833561478781614759565b9250602084013561479781614759565b915060408401356147a781614759565b809150509250925092565b600080600080608085870312156147c857600080fd5b6147d185614544565b9350602085013592506147e660408601614544565b91506147f460608601614544565b905092959194509250565b6000806040838503121561481257600080fd5b823591506146ed60208401614544565b60006020828403121561483457600080fd5b81356131dd81614759565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600060c0828403121561488057600080fd5b82601f83011261488f57600080fd5b60405160c0810181811067ffffffffffffffff821117156148d9577f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040528060c08401858111156148ee57600080fd5b845b818110156149085780358352602092830192016148f0565b509195945050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60008282101561498357614983614942565b500390565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04831182151516156149c0576149c0614942565b500290565b6000826149fb577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b60008219821115614a1357614a13614942565b500190565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff821415614a4a57614a4a614942565b5060010190565b600060208284031215614a6357600080fd5b5051919050565b60005b83811015614a85578181015183820152602001614a6d565b838111156110485750506000910152565b60008251614aa8818460208701614a6a565b9190910192915050565b600060208284031215614ac457600080fd5b81516131dd81614759565b60008060408385031215614ae257600080fd5b505080516020909101519092909150565b6020815260008251806020840152614b12816040850160208701614a6a565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016919091016040019291505056fea26469706673582212205efa6d08b2eb70ca21abb4b800afe279cbd5aa94eedb9e5c5b96bc1201312def64736f6c634300080a0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000ff5b4bcbf765fe363269114e1c765229a29edefd00000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000001a000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000260000000000000000000000000c14900dfb1aa54e7674e1ecf9ce02b3b35157ba500000000000000000000000000000000000000000000000000000000000000020000000000000000000000003432b6a60d23ca0dfca7761b7ab56459d9c964d00000000000000000000000001b40183efb4dd766f11bda7a7c3ad8982e9984210000000000000000000000000000000000000000000000000000000000000002000000000000000000000000b1748c79709f4ba2dd82834b8c82d4a505003f270000000000000000000000009520b477aa81180e6ddc006fc09fb6d3eb4e807a000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000a86cc92e3da00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000278dc748eda1d8efef1adfb518542612b49fcd340000000000000000000000000000000000000000000000000000000000000000
-----Decoded View---------------
Arg [0] : _owner (address): 0xfF5B4BCbf765FE363269114e1c765229a29eDeFD
Arg [1] : _rewardTokens (address[]): 0x3432B6A60D23Ca0dFCa7761B7ab56459D9C964D0,0x1b40183EFB4Dd766f11bDa7A7c3AD8982e998421
Arg [2] : _rewardManagers (address[]): 0xB1748C79709f4Ba2Dd82834B8c82D4a505003f27,0x9520b477Aa81180E6DdC006Fc09Fb6d3eb4e807A
Arg [3] : _rewardRates (uint256[]): 11574074074074,0
Arg [4] : _gaugeControllers (address[]): 0x0000000000000000000000000000000000000000,0x0000000000000000000000000000000000000000
Arg [5] : _rewardDistributors (address[]): 0x278dC748edA1d8eFEf1aDFB518542612b49Fcd34,0x0000000000000000000000000000000000000000
Arg [6] : _stakingToken (address): 0xc14900dFB1Aa54e7674e1eCf9ce02b3b35157ba5
-----Encoded View---------------
22 Constructor Arguments found :
Arg [0] : 000000000000000000000000ff5b4bcbf765fe363269114e1c765229a29edefd
Arg [1] : 00000000000000000000000000000000000000000000000000000000000000e0
Arg [2] : 0000000000000000000000000000000000000000000000000000000000000140
Arg [3] : 00000000000000000000000000000000000000000000000000000000000001a0
Arg [4] : 0000000000000000000000000000000000000000000000000000000000000200
Arg [5] : 0000000000000000000000000000000000000000000000000000000000000260
Arg [6] : 000000000000000000000000c14900dfb1aa54e7674e1ecf9ce02b3b35157ba5
Arg [7] : 0000000000000000000000000000000000000000000000000000000000000002
Arg [8] : 0000000000000000000000003432b6a60d23ca0dfca7761b7ab56459d9c964d0
Arg [9] : 0000000000000000000000001b40183efb4dd766f11bda7a7c3ad8982e998421
Arg [10] : 0000000000000000000000000000000000000000000000000000000000000002
Arg [11] : 000000000000000000000000b1748c79709f4ba2dd82834b8c82d4a505003f27
Arg [12] : 0000000000000000000000009520b477aa81180e6ddc006fc09fb6d3eb4e807a
Arg [13] : 0000000000000000000000000000000000000000000000000000000000000002
Arg [14] : 00000000000000000000000000000000000000000000000000000a86cc92e3da
Arg [15] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [16] : 0000000000000000000000000000000000000000000000000000000000000002
Arg [17] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [18] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [19] : 0000000000000000000000000000000000000000000000000000000000000002
Arg [20] : 000000000000000000000000278dc748eda1d8efef1adfb518542612b49fcd34
Arg [21] : 0000000000000000000000000000000000000000000000000000000000000000
Deployed Bytecode Sourcemap
98632:523:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;56872:529;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;59082:313;;;;;;:::i;:::-;;:::i;:::-;;;1374:25:1;;;1362:2;1347:18;59082:313:0;1228:177:1;55151:109:0;;;:::i;:::-;;;;;;;:::i;46389:141::-;;;;;;:::i;:::-;;:::i;:::-;;92638:165;;;;;;:::i;:::-;;:::i;57465:339::-;;;:::i;89376:133::-;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;59614:179::-;;;;;;:::i;:::-;;:::i;54815:298::-;;;;;;:::i;:::-;;:::i;:::-;;;3795:14:1;;3788:22;3770:41;;3758:2;3743:18;54815:298:0;3630:187:1;51954:60:0;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;3998:42:1;3986:55;;;3968:74;;3956:2;3941:18;51954:60:0;3822:226:1;97469:357:0;;;;;;:::i;:::-;;:::i;60710:1766::-;;;;;;:::i;:::-;;:::i;72040:161::-;;;;;;:::i;:::-;;:::i;58518:127::-;;;;;;:::i;:::-;58611:26;;58584:7;58611:26;;;:17;:26;;;;;;;58518:127;50696:48;;50738:6;50696:48;;50324:49;;;;;;:::i;:::-;;;;;;;;;;;;;;;;60314:181;;;;;;:::i;:::-;;:::i;46157:29::-;;;;;;;;;84207:2377;;;:::i;58232:111::-;58313:22;;58232:111;;50577:55;;;;;;:::i;:::-;;;;;;;;;;;;;;49603:36;;;;;;55975:681;;;:::i;82254:26::-;;;;;;;;;;;;82371:53;;;;;;:::i;:::-;;:::i;:::-;;;;5213:25:1;;;5269:2;5254:18;;5247:34;;;;5297:18;;;5290:34;;;;5355:2;5340:18;;5333:34;5398:3;5383:19;;5376:35;5200:3;5185:19;82371:53:0;4954:463:1;46538:271:0;;;:::i;51549:52::-;;;;;;:::i;:::-;;;;;;;;;;;;;;60503:199;;;;;;:::i;:::-;;:::i;72540:1013::-;;;;;;:::i;:::-;;:::i;86692:2589::-;;;;;;:::i;:::-;;:::i;:::-;;;;5624:25:1;;;5680:2;5665:18;;5658:34;;;;5708:18;;;5701:34;5612:2;5597:18;86692:2589:0;5422:319:1;46130:20:0;;;;;;;;;72250:161;;;;;;:::i;:::-;;:::i;52158:26::-;;;;;;;;;59896:224;;;;;;:::i;:::-;;:::i;71895:97::-;;;:::i;49692:55::-;;;;;;62620:278;;;;;;:::i;:::-;;:::i;91250:1259::-;;;;;;:::i;:::-;;:::i;49524:61::-;;;;;;66765:247;;;;;;:::i;:::-;;:::i;49370:29::-;;;;;;89585:133;;;;;;:::i;:::-;89682:21;;89655:7;89682:21;;;:12;:21;;;;;:28;;89585:133;71386:311;;;;;;:::i;:::-;;:::i;49450:50::-;;;;;;59440:166;;;;;;:::i;:::-;;:::i;74596:483::-;;;;;;:::i;:::-;;:::i;63766:419::-;;;;;;:::i;:::-;;:::i;58066:128::-;;;;;;:::i;:::-;58160:26;;58133:7;58160:26;;;:17;:26;;;;;;;58066:128;75154:207;;;;;;:::i;:::-;;:::i;57902:113::-;57984:23;;57902:113;;71790:97;;;:::i;95094:234::-;;;;;;:::i;:::-;;:::i;63066:610::-;;;;;;:::i;:::-;;:::i;97862:298::-;;;;;;:::i;:::-;;:::i;49336:27::-;;;;;;49830:51;;;;;;49906:59;;;;;;55453:452;;;;;;:::i;:::-;;:::i;70151:761::-;;;;;;:::i;:::-;;:::i;73561:958::-;;;;;;:::i;:::-;;:::i;70920:277::-;;;:::i;56872:529::-;56926:27;56966;56996:17;:15;:17::i;:::-;57051:12;:19;56966:47;;-1:-1:-1;57037:34:0;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;57037:34:0;-1:-1:-1;57088:26:0;;;57117:1;57088:26;;;:17;:26;;;;;;57024:47;;-1:-1:-1;57088:30:0;57084:310;;57139:9;57134:249;57158:12;:19;57154:23;;57134:249;;;57348:16;;;;;;;:7;:16;;;;;;;;:19;;;;;;;;;57267:32;;;:23;:32;;;;;:35;;;;;;;;;57251:13;;57307:4;;57267:35;57251:10;;57365:1;;57251:13;;;;;;:::i;:::-;;;;;;;:51;;;;:::i;:::-;57221:26;;;;;;;:17;:26;;;;;;:82;;;;:::i;:::-;57220:91;;;;:::i;:::-;57219:148;;;;:::i;:::-;57203:10;57214:1;57203:13;;;;;;;;:::i;:::-;;;;;;;;;;:164;57179:3;;;;:::i;:::-;;;;57134:249;;;;57084:310;56955:446;56872:529;;;:::o;59082:313::-;59191:19;;59332:28;;59141:7;;59168:218;;59285:42;49301:4;59191:19;59285:42;:::i;:::-;59277:51;;:4;:51;:::i;:::-;59276:84;;;;:::i;:::-;59225:150;;49301:4;59225:150;:::i;:::-;59168:8;:218::i;:::-;59161:225;59082:313;-1:-1:-1;;59082:313:0:o;55151:109::-;55204:16;55240:12;55233:19;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;55151:109;:::o;46389:141::-;46869:5;;;;46855:10;:19;46847:79;;;;;;;10474:2:1;46847:79:0;;;10456:21:1;10513:2;10493:18;;;10486:30;10552:34;10532:18;;;10525:62;10623:17;10603:18;;;10596:45;10658:19;;46847:79:0;;;;;;;;;46461:14:::1;:23:::0;;;::::1;;::::0;::::1;::::0;;::::1;::::0;;;46500:22:::1;::::0;3968:74:1;;;46500:22:0::1;::::0;3956:2:1;3941:18;46500:22:0::1;;;;;;;46389:141:::0;:::o;92638:165::-;45064:1;45670:7;;:19;;45662:63;;;;;;;10890:2:1;45662:63:0;;;10872:21:1;10929:2;10909:18;;;10902:30;10968:33;10948:18;;;10941:61;11019:18;;45662:63:0;10688:355:1;45662:63:0;45064:1;45803:18;;92725:70:::1;92738:10;::::0;92762:9;92773:4;92779:15:::1;92725:12;:70::i;:::-;-1:-1:-1::0;;45020:1:0;45982:7;:22;92638:165::o;57465:339::-;57615:17;:24;57520:41;;57601:39;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;57601:39:0;;57574:66;;57658:9;57653:144;57677:17;:24;57673:28;;57653:144;;;50738:6;57753:14;57765:1;57753:11;:14::i;:::-;:32;;;;:::i;:::-;57723:24;57748:1;57723:27;;;;;;;;:::i;:::-;;;;;;;;;;:62;57703:3;;;;:::i;:::-;;;;57653:144;;;;57465:339;:::o;89376:133::-;89480:21;;;;;;;:12;:21;;;;;;;;89473:28;;;;;;;;;;;;;;;;;89440:20;;89473:28;;89480:21;;89473:28;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;89376:133;;;:::o;59614:179::-;59729:32;;;59683:7;59729:32;;;:17;:32;;;;;;59711:15;;49301:4;;59711:50;;;:::i;:::-;59710:75;;;;:::i;54815:298::-;54911:4;54946:5;;;54931:20;;;54946:5;;54931:20;54927:136;;;-1:-1:-1;54960:4:0;54953:11;;54927:136;55002:48;:33;;;;;;;:14;:33;;;;;;;;:48;;;;54998:65;;;-1:-1:-1;55059:4:0;55052:11;;54998:65;-1:-1:-1;55099:5:0;54815:298;;;;:::o;97469:357::-;53055:12;;;;;;;;:20;;:12;:20;53047:49;;;;;;;11250:2:1;53047:49:0;;;11232:21:1;11289:2;11269:18;;;11262:30;11328:18;11308;;;11301:46;11364:18;;53047:49:0;11048:340:1;53047:49:0;97622:40:::1;::::0;::::1;;::::0;;;:24:::1;:40;::::0;;;;;;;97663:10:::1;97622:52:::0;;;;;;;;::::1;;:83:::0;::::1;;;-1:-1:-1::0;97694:10:0::1;97678:27;::::0;;;:15:::1;:27;::::0;;;;;::::1;;97622:83;97614:122;;;::::0;::::1;::::0;;11595:2:1;97614:122:0::1;::::0;::::1;11577:21:1::0;11634:2;11614:18;;;11607:30;11673:28;11653:18;;;11646:56;11719:18;;97614:122:0::1;11393:350:1::0;97614:122:0::1;97747:71;97760:14;97776:10;97788:6;97796:4;97802:15;97747:12;:71::i;:::-;97469:357:::0;;;;:::o;60710:1766::-;60934:34;;;;60773:24;60934:34;;;:25;:34;;;;;;60773:24;;;;60934:34;60999:23;;60998:81;;61053:5;;:26;;;;;:5;3986:55:1;;;61053:26:0;;;3968:74:1;61053:5:0;;;;:15;;3941:18:1;;61053:26:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;60998:81;;;61026:5;;:24;;;;;:5;3986:55:1;;;61026:24:0;;;3968:74:1;61026:5:0;;;;:15;;3941:18:1;;61026:24:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;60979:100;;61185:19;49301:4;61309:5;;;;;;;;;;;:17;;;:19;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:42;;;;:::i;:::-;61250:24;;61227:20;;61208:39;;:16;:39;:::i;:::-;:66;;;;:::i;:::-;61207:145;;;;:::i;:::-;61185:167;-1:-1:-1;61461:19:0;;61676:23;;;;61675:94;;61734:35;61759:9;61734:24;:35::i;:::-;61675:94;;;61703:28;61723:7;61703:19;:28::i;:::-;61646:123;-1:-1:-1;61790:30:0;;61786:323;;61841:27;61915:26;61872:39;49301:4;61872:16;:39;:::i;:::-;61871:70;;;;:::i;:::-;61841:100;;49301:4;62015:20;;61993:19;:42;;;;:::i;:::-;61992:67;;;;:::i;:::-;61978:81;;61821:254;61786:323;;;62108:1;62094:15;;61786:323;61491:699;62277:11;62263;:25;:53;;62305:11;62263:53;;;62291:11;62263:53;62243:74;;62407:20;;62388:16;:39;62384:84;;;62448:20;;62429:39;;62384:84;60799:1677;;;;60710:1766;;;:::o;72040:161::-;52697:5;;;;52683:10;:19;;:79;;-1:-1:-1;52720:42:0;52706:10;:56;52683:79;52675:113;;;;;;;12139:2:1;52675:113:0;;;12121:21:1;12178:2;12158:18;;;12151:30;12217:23;12197:18;;;12190:51;12258:18;;52675:113:0;11937:345:1;52675:113:0;72160:33:::1;;;::::0;;;:15:::1;:33;::::0;;;;;;72123:70;;::::1;72160:33;::::0;;::::1;72159:34;72123:70;::::0;;72040:161::o;60314:181::-;60381:7;49301:4;60435:28;;60409:23;60424:7;60409:14;:23::i;:::-;:54;;;;:::i;84207:2377::-;84263:7;84344:25;86511:12;;;;;;;;;;;:26;;;:28;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;55975:681::-;56023:41;56081:23;;56108:1;56081:28;:59;;;-1:-1:-1;56113:22:0;;:27;56081:59;56077:572;;;56164:21;56157:28;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;55975:681;:::o;56077:572::-;56268:12;:19;56254:34;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;56254:34:0;;56227:61;;56308:9;56303:289;56327:21;:28;56323:32;;56303:289;;;56535:22;;56510:14;56522:1;56510:11;:14::i;:::-;56492;;56463:26;:24;:26::i;:::-;:43;;;;:::i;:::-;56462:62;;;;:::i;:::-;:69;;56527:4;56462:69;:::i;:::-;56461:96;;;;:::i;:::-;56411:21;56433:1;56411:24;;;;;;;;:::i;:::-;;;;;;;;;:165;;;;:::i;:::-;56381:24;56406:1;56381:27;;;;;;;;:::i;:::-;;;;;;;;;;:195;56357:3;;;;:::i;:::-;;;;56303:289;;82371:53;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;82371:53:0;;-1:-1:-1;82371:53:0;;;:::o;46538:271::-;46607:14;;;;46593:10;:28;46585:94;;;;;;;12489:2:1;46585:94:0;;;12471:21:1;12528:2;12508:18;;;12501:30;12567:34;12547:18;;;12540:62;12638:23;12618:18;;;12611:51;12679:19;;46585:94:0;12287:417:1;46585:94:0;46708:5;;;46715:14;46695:35;;;46708:5;;;;12944:34:1;;46715:14:0;;;;13009:2:1;12994:18;;12987:43;46695:35:0;;12856:18:1;46695:35:0;;;;;;;46749:14;;;;46741:22;;;;;;46749:14;;;46741:22;;;;46774:27;;;46538:271::o;60503:199::-;60581:7;49301:4;60642:28;;60609:30;60625:13;60609:15;:30::i;72540:1013::-;52900:5;;72626:12;;52900:5;;52886:10;:19;;:74;;;52909:51;52927:10;52939:20;52909:17;:51::i;:::-;52878:107;;;;;;;13243:2:1;52878:107:0;;;13225:21:1;13282:2;13262:18;;;13255:30;13321:22;13301:18;;;13294:50;13361:18;;52878:107:0;13041:344:1;52878:107:0;72708:18:::1;72750:9:::0;72745:192:::1;72769:12;:19:::0;72765:23;::::1;72745:192;;;72833:12;72814:31;;:12;72827:1;72814:15;;;;;;;;:::i;:::-;;::::0;;;::::1;::::0;;;::::1;::::0;::::1;;:31;72810:116;;;72882:4;72866:20;;72905:5;;72810:116;72790:3:::0;::::1;::::0;::::1;:::i;:::-;;;;72745:192;;;;73163:13;:59;;;;-1:-1:-1::0;73180:42:0::1;:28:::0;;::::1;;::::0;;;:14:::1;:28;::::0;;;;;::::1;73212:10;73180:42;73163:59;73162:123;;;;73246:13;73245:14;:39;;;;-1:-1:-1::0;73278:5:0::1;::::0;::::1;;73264:10;:19;73245:39;73140:406;;;73316:66;73344:12;73358:10;73370:11;73316:27;:66::i;73140:406::-;73498:36;::::0;::::1;::::0;;13592:2:1;73498:36:0::1;::::0;::::1;13574:21:1::0;13631:2;13611:18;;;13604:30;13670:28;13650:18;;;13643:56;13716:18;;73498:36:0::1;13390:350:1::0;52996:1:0::1;72540:1013:::0;;;:::o;86692:2589::-;86995:26;;;86793:27;86995:26;;;:17;:26;;;;;;;86793:27;87182:24;87013:7;87182:15;:24::i;:::-;87267:26;;;87219:33;87267:26;;;:17;:26;;;;;;87159:47;;-1:-1:-1;87219:33:0;87267:31;:66;;;;-1:-1:-1;87302:26:0;;;;;;;:17;:26;;;;;;:31;87267:66;87263:386;;;-1:-1:-1;87487:20:0;87263:386;;;87601:31;;;;;;;:22;:31;;;;;;87636:1;;87578:54;;:20;:54;:::i;:::-;87577:60;;;;:::i;:::-;87549:88;;87263:386;87784:1;87762:23;;87801:9;87796:1478;87820:21;;;;;;;:12;:21;;;;;:28;87816:32;;87796:1478;;;87901:21;;;87870:28;87901:21;;;:12;:21;;;;;:24;;87923:1;;87901:24;;;;;;:::i;:::-;;;;;;;;;;;87870:55;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;87940:23;87966:9;:25;;;87940:51;;88081:15;88051:9;:26;;;:45;88047:947;;88284:26;;;;88253:28;;;;;;;:19;:28;;;;;;:57;88249:730;;;88392:28;;;88334:26;88392:28;;;:19;:28;;;;;;88363:26;;;;:57;;88392:28;88363:57;:::i;:::-;88334:86;;88443:25;88489:9;:26;;;88471:15;:44;;;;:::i;:::-;88443:72;-1:-1:-1;88605:17:0;88667:40;88443:72;49301:4;88667:40;:::i;:::-;88626:36;88644:18;88626:15;:36;:::i;:::-;88625:83;;;;:::i;:::-;88605:103;-1:-1:-1;88762:38:0;88783:17;88762:18;:38;:::i;:::-;88749:52;;:9;:52;:::i;:::-;88731:70;;88311:510;;;88249:730;;;-1:-1:-1;49301:4:0;88249:730;89030:19;;;;89010:17;49301:4;89112:43;89130:25;89112:15;:43;:::i;:::-;89099:57;;:9;:57;:::i;:::-;89098:82;;;;:::i;:::-;89064:116;-1:-1:-1;89217:45:0;89064:116;89217:19;:45;:::i;:::-;89195:67;;87855:1419;;;;87850:3;;;;;:::i;:::-;;;;87796:1478;;;;86922:2359;86692:2589;;;;;:::o;72250:161::-;52697:5;;;;52683:10;:19;;:79;;-1:-1:-1;52720:42:0;52706:10;:56;52683:79;52675:113;;;;;;;12139:2:1;52675:113:0;;;12121:21:1;12178:2;12158:18;;;12151:30;12217:23;12197:18;;;12190:51;12258:18;;52675:113:0;11937:345:1;52675:113:0;72371:32:::1;;;::::0;;;:19:::1;:32;::::0;;;;;;72335:68;;::::1;72371:32;::::0;;::::1;72370:33;72335:68;::::0;;72250:161::o;59896:224::-;59962:7;60096:15;;60065:28;;:46;;;;:::i;:::-;59990:5;;:24;;;;;:5;3986:55:1;;;59990:24:0;;;3968:74:1;49301:4:0;;;;59990:5;;;:15;;3941:18:1;;59990:24:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:47;;;;:::i;71895:97::-;52697:5;;;;52683:10;:19;;:79;;-1:-1:-1;52720:42:0;52706:10;:56;52683:79;52675:113;;;;;;;12139:2:1;52675:113:0;;;12121:21:1;12178:2;12158:18;;;12151:30;12217:23;12197:18;;;12190:51;12258:18;;52675:113:0;11937:345:1;52675:113:0;71972:12:::1;::::0;;71956:28;;::::1;71972:12;::::0;;;::::1;;;71971:13;71956:28:::0;;::::1;;::::0;;71895:97::o;62620:278::-;62704:33;;;;;;;:15;:33;;;;;;;;62696:70;;;;;;;13947:2:1;62696:70:0;;;13929:21:1;13986:2;13966:18;;;13959:30;14025:26;14005:18;;;13998:54;14069:18;;62696:70:0;13745:348:1;62696:70:0;62860:10;62835:36;;;;:24;:36;;;;;;;;;:54;;;;;;;;;;;;;;;62834:55;62777:112;;;;;;;62620:278::o;91250:1259::-;91331:10;91343:4;53199:42;53223:7;53232:8;53199:23;:42::i;:::-;91408:28:::1;91438:21:::0;91463:29:::1;91473:10;91485:6;91463:9;:29::i;:::-;91407:85;;;;91542:15;91582:8;91560:9;:19;;;:30;;;;:::i;:::-;91542:48:::0;-1:-1:-1;91760:12:0::1;::::0;91720:91:::1;::::0;91760:12;;::::1;;;91775:10;91795:4;91802:8:::0;91720:31:::1;:91::i;:::-;91895:186;::::0;;::::1;::::0;::::1;::::0;;;;;::::1;91942:25:::0;;::::1;::::0;91895:186;;::::1;::::0;;;;;;;;92004:26;;::::1;::::0;91895:186;;;;;92045:25;;::::1;::::0;91895:186;;;;91866:10:::1;-1:-1:-1::0;91853:24:0;;;:12:::1;:24:::0;;;;;;;:39;;91878:13;;91853:39;::::1;;;;;:::i;:::-;;;;;;;;;;;:228;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;92152:8;92125:23;;:35;;;;;;;:::i;:::-;::::0;;;-1:-1:-1;;92189:10:0::1;92171:29;::::0;;;:17:::1;:29;::::0;;;;:41;;92204:8;;92171:29;:41:::1;::::0;92204:8;;92171:41:::1;:::i;:::-;::::0;;;-1:-1:-1;;92284:10:0::1;92238:17;92258:37:::0;;;:25:::1;:37;::::0;;;;;::::1;;92314:23:::0;;92310:69:::1;;92339:28;::::0;::::1;;::::0;;;:17:::1;:28:::0;;;;;:40;;92371:8;;92339:28;:40:::1;::::0;92371:8;;92339:40:::1;:::i;:::-;::::0;;;-1:-1:-1;;92310:69:0::1;92223:168;92459:42;92483:10;92495:5;92459:23;:42::i;:::-;91356:1153;;;91250:1259:::0;;;;:::o;66765:247::-;66844:16;45064:1;45670:7;;:19;;45662:63;;;;;;;10890:2:1;45662:63:0;;;10872:21:1;10929:2;10909:18;;;10902:30;10968:33;10948:18;;;10941:61;11019:18;;45662:63:0;10688:355:1;45662:63:0;45064:1;45803:18;;66881:23:::1;::::0;;;::::1;;;:32;66873:70;;;::::0;::::1;::::0;;14644:2:1;66873:70:0::1;::::0;::::1;14626:21:1::0;14683:2;14663:18;;;14656:30;14722:27;14702:18;;;14695:55;14767:18;;66873:70:0::1;14442:349:1::0;66873:70:0::1;66961:43;66972:10;66984:19;66961:10;:43::i;:::-;45020:1:::0;45982:7;:22;66954:50;66765:247;-1:-1:-1;;66765:247:0:o;71386:311::-;52697:5;;;;52683:10;:19;;:79;;-1:-1:-1;52720:42:0;52706:10;:56;52683:79;52675:113;;;;;;;12139:2:1;52675:113:0;;;12121:21:1;12178:2;12158:18;;;12151:30;12217:23;12197:18;;;12190:51;12258:18;;52675:113:0;11937:345:1;52675:113:0;71549:13:::1;:30:::0;;71639:50;::::1;;::::0;::::1;::::0;71590:38;::::1;;::::0;::::1;::::0;71549:30;::::1;;::::0;::::1;71590:38:::0;;;;;;;;;;;;;;;::::1;71639:50:::0;;;::::1;;::::0;;71386:311::o;59440:166::-;59548:26;;;59502:7;59548:26;;;:17;:26;;;;;;59530:15;;49301:4;;59530:44;;;:::i;74596:483::-;52900:5;;74762:20;;52900:5;;52886:10;:19;;:74;;;52909:51;52927:10;52939:20;52909:17;:51::i;:::-;52878:107;;;;;;;13243:2:1;52878:107:0;;;13225:21:1;13282:2;13262:18;;;13255:30;13321:22;13301:18;;;13294:50;13361:18;;52878:107:0;13041:344:1;52878:107:0;74813:42:::1;::::0;::::1;;::::0;;;:20:::1;:42;::::0;;;;;74795:17:::1;:61:::0;;74859:9;;74813:42;74795:61;::::1;;;;;:::i;:::-;;;;;;;;:73;;;;74942:25;74879:16;74896:20;:42;74917:20;74896:42;;;;;;;;;;;;;;;;74879:60;;;;;;;;:::i;:::-;;::::0;;;::::1;::::0;;;;;;::::1;:88:::0;;;::::1;;::::0;;::::1;;::::0;;74997:42;;::::1;::::0;;:20:::1;:42:::0;;;;;;;74978:18:::1;:62:::0;;75043:28;;74997:42;74978:62;::::1;;;;;:::i;:::-;;;;;;;;;:93;;;;;;;;;;;;;;;;;;74596:483:::0;;;;;:::o;63766:419::-;63846:34;;;;;;;:19;:34;;;;;;;;63838:60;;;;;;;14998:2:1;63838:60:0;;;14980:21:1;15037:2;15017:18;;;15010:30;15076:15;15056:18;;;15049:43;15109:18;;63838:60:0;14796:337:1;63838:60:0;63917:36;;;;;;;:21;:36;;;;;;;;63954:10;63917:48;;;;;;;;;;63909:90;;;;;;;15340:2:1;63909:90:0;;;15322:21:1;15379:2;15359:18;;;15352:30;15418:31;15398:18;;;15391:59;15467:18;;63909:90:0;15138:353:1;63909:90:0;64036:10;64010:37;;;;:25;:37;;;;;;;;:53;;;;:37;:53;;;;;;;;64148:17;:29;;;;;;64112:32;;;;;;;;:65;;64148:29;;64112:32;;:65;;64148:29;;64112:65;:::i;:::-;;;;-1:-1:-1;;;63766:419:0:o;75154:207::-;52900:5;;75262:20;;52900:5;;52886:10;:19;;:74;;;52909:51;52927:10;52939:20;52909:17;:51::i;:::-;52878:107;;;;;;;13243:2:1;52878:107:0;;;13225:21:1;13282:2;13262:18;;;13255:30;13321:22;13301:18;;;13294:50;13361:18;;52878:107:0;13041:344:1;52878:107:0;-1:-1:-1;75295:36:0::1;::::0;;::::1;;::::0;;;:14:::1;:36;::::0;;;;:58;;;::::1;::::0;;;::::1;;::::0;;75154:207::o;71790:97::-;52697:5;;;;52683:10;:19;;:79;;-1:-1:-1;52720:42:0;52706:10;:56;52683:79;52675:113;;;;;;;12139:2:1;52675:113:0;;;12121:21:1;12178:2;12158:18;;;12151:30;12217:23;12197:18;;;12190:51;12258:18;;52675:113:0;11937:345:1;52675:113:0;71865:14:::1;::::0;;71847:32;;::::1;71865:14;::::0;;::::1;71864:15;71847:32;::::0;;71790:97::o;95094:234::-;45064:1;45670:7;;:19;;45662:63;;;;;;;10890:2:1;45662:63:0;;;10872:21:1;10929:2;10909:18;;;10902:30;10968:33;10948:18;;;10941:61;11019:18;;45662:63:0;10688:355:1;45662:63:0;45064:1;45803:18;;95204:17:::1;::::0;;;::::1;;;:26;95196:57;;;::::0;::::1;::::0;;15698:2:1;95196:57:0::1;::::0;::::1;15680:21:1::0;15737:2;15717:18;;;15710:30;15776:20;15756:18;;;15749:48;15814:18;;95196:57:0::1;15496:342:1::0;95196:57:0::1;95264:56;95280:10;95292:19;95313:6;95264:15;:56::i;63066:610::-:0;63165:10;63145:31;;;;:19;:31;;;;;;;;63137:57;;;;;;;14998:2:1;63137:57:0;;;14980:21:1;15037:2;15017:18;;;15010:30;15076:15;15056:18;;;15049:43;15109:18;;63137:57:0;14796:337:1;63137:57:0;63280:10;63258:33;;;;:21;:33;;;;;;;;;:49;;;;;;;;;;;;;;;;63257:50;63205:102;;;;;;;63410:25;:41;;;;;;;;:55;63406:263;;;63481:41;;;63533:1;63481:41;;;:25;:41;;;;;;;;:54;;;;;;63624:17;:33;;;;;;63609:10;63591:29;;;;;;;:66;;63624:33;;63591:29;;:66;;63624:33;;63591:66;:::i;63406:263::-;63066:610;:::o;97862:298::-;53055:12;;;;;;;;:20;;:12;:20;53047:49;;;;;;;11250:2:1;53047:49:0;;;11232:21:1;11289:2;11269:18;;;11262:30;11328:18;11308;;;11301:46;11364:18;;53047:49:0;11048:340:1;53047:49:0;97976:40:::1;::::0;::::1;;::::0;;;:24:::1;:40;::::0;;;;;;;98017:10:::1;97976:52:::0;;;;;;;;::::1;;:83:::0;::::1;;;-1:-1:-1::0;98048:10:0::1;98032:27;::::0;;;:15:::1;:27;::::0;;;;;::::1;;97976:83;97968:122;;;::::0;::::1;::::0;;11595:2:1;97968:122:0::1;::::0;::::1;11577:21:1::0;11634:2;11614:18;;;11607:30;11673:28;11653:18;;;11646:56;11719:18;;97968:122:0::1;11393:350:1::0;97968:122:0::1;98101:51;98117:14;98133:10;98145:6;98101:15;:51::i;:::-;97862:298:::0;;:::o;55453:452::-;55514:16;55543:32;55578:16;55595:9;55578:27;;;;;;;;:::i;:::-;;;;;;;;;;;;;;-1:-1:-1;55620:38:0;;55616:282;;55801:4;55759:27;55787:9;55759:38;;;;;;;;:::i;:::-;;;;;;;;;55708:24;55687:67;;;:69;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:110;;;;:::i;:::-;55686:119;;;;:::i;:::-;55675:130;;55616:282;;;55858:17;55876:9;55858:28;;;;;;;;:::i;:::-;;;;;;;;;55847:39;;55532:373;55453:452;;;:::o;70151:761::-;70268:9;70263:642;70287:16;:23;70283:27;;70263:642;;;70332:32;70367:16;70384:1;70367:19;;;;;;;;:::i;:::-;;;;;;;;;;;;;;-1:-1:-1;70405:38:0;;70401:493;;70468:12;:61;;;;70503:22;70526:1;70503:25;;;;;;;;:::i;:::-;;;;;;;;;70485:15;:43;70468:61;70464:415;;;70643:106;;;;;70726:4;70643:106;;;16017:74:1;70733:15:0;16107:18:1;;;16100:34;70643:74:0;;;;;;15990:18:1;;70643:106:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;70610:27;70638:1;70610:30;;;;;;;;:::i;:::-;;;;;;;;:139;;;;70821:24;70800:57;;;:59;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;70772:22;70795:1;70772:25;;;;;;;;:::i;:::-;;;;;;;;;;:87;70464:415;-1:-1:-1;70312:3:0;;;;:::i;:::-;;;;70263:642;;73561:958;52697:5;;;;52683:10;:19;;:79;;-1:-1:-1;52720:42:0;52706:10;:56;52683:79;52675:113;;;;;;;12139:2:1;52675:113:0;;;12121:21:1;12178:2;12158:18;;;12151:30;12217:23;12197:18;;;12190:51;12258:18;;52675:113:0;11937:345:1;52675:113:0;73970:13;;49301:4:::1;-1:-1:-1::0;73970:37:0::1;73962:69;;;::::0;::::1;::::0;;16347:2:1;73962:69:0::1;::::0;::::1;16329:21:1::0;16386:2;16366:18;;;16359:30;16425:21;16405:18;;;16398:49;16464:18;;73962:69:0::1;16145:343:1::0;73962:69:0::1;74155:13:::0;;::::1;::::0;74172:1:::1;-1:-1:-1::0;74155:18:0;::::1;::::0;74154:44:::1;;-1:-1:-1::0;74179:13:0;;::::1;::::0;74196:1:::1;-1:-1:-1::0;74179:18:0::1;74154:44;74146:69;;;::::0;::::1;::::0;;17036:2:1;74146:69:0::1;::::0;::::1;17018:21:1::0;17075:2;17055:18;;;17048:30;17114:14;17094:18;;;17087:42;17146:18;;74146:69:0::1;16834:336:1::0;74146:69:0::1;74250:13:::0;;74228:19:::1;:35:::0;74250:13:::1;74297::::0;::::1;::::0;74274:20:::1;:36:::0;74352:13;;::::1;::::0;74321:28:::1;:44:::0;74403:13;;::::1;::::0;74376:24:::1;:40:::0;74458:13;;::::1;::::0;74427:28:::1;:44:::0;74498:13;::::1;::::0;74482::::1;:29:::0;73561:958::o;70920:277::-;71003:25;71022:5;71003:18;:25::i;:::-;71064:12;;71045:15;:31;71041:149;;71093:14;:12;:14::i;:::-;70920:277::o;71041:149::-;71149:29;:27;:29::i;522:106::-;580:7;611:1;607;:5;:13;;619:1;607:13;;;615:1;607:13;600:20;522:106;-1:-1:-1;;;522:106:0:o;93192:1728::-;93404:14;93420:4;53199:42;53223:7;53232:8;53199:23;:42::i;:::-;93445:13:::1;::::0;;;::::1;;;:22;::::0;:61:::1;;-1:-1:-1::0;93487:10:0::1;93471:27;::::0;;;:15:::1;:27;::::0;;;;;::::1;;:35;;:27:::0;:35:::1;93445:61;93437:104;;;::::0;::::1;::::0;;17377:2:1;93437:104:0::1;::::0;::::1;17359:21:1::0;17416:2;17396:18;;;17389:30;17455:32;17435:18;;;17428:60;17505:18;;93437:104:0::1;17175:354:1::0;93437:104:0::1;93568:13;;93560:4;:21;;93552:60;;;::::0;::::1;::::0;;17736:2:1;93552:60:0::1;::::0;::::1;17718:21:1::0;17775:2;17755:18;;;17748:30;17814:28;17794:18;;;17787:56;17860:18;;93552:60:0::1;17534:350:1::0;93552:60:0::1;93639:28;;93631:4;:36;;93623:75;;;::::0;::::1;::::0;;18091:2:1;93623:75:0::1;::::0;::::1;18073:21:1::0;18130:2;18110:18;;;18103:30;18169:29;18149:18;;;18142:57;18216:18;;93623:75:0::1;17889:351:1::0;93623:75:0::1;93821:12;::::0;93781:96:::1;::::0;93821:12;;::::1;;;93836:14:::0;93860:4:::1;93867:9:::0;93781:31:::1;:96::i;:::-;93937:23;93963:20;93978:4;93963:14;:20::i;:::-;94082:33;::::0;::::1;93994:14;94082:33:::0;;;:17:::1;:33;::::0;;;;;;;;94021:95;;18491:66:1;18478:2;18474:15;;;18470:88;94021:95:0;;::::1;18458:101:1::0;;;;18575:12;;;18568:28;;;18612:12;;;18605:28;;;18649:12;;;18642:28;93937:46:0;;-1:-1:-1;93994:14:0;18686:13:1;;94021:95:0::1;::::0;;;;;::::1;::::0;;;;;;94011:106;;94021:95:::1;94011:106:::0;;::::1;::::0;94174:28:::1;::::0;::::1;;::::0;;;:12:::1;:28:::0;;;;;94208:164:::1;::::0;::::1;::::0;;;;;;;::::1;::::0;;;;;;;;;94011:106;;-1:-1:-1;94174:28:0;94208:164;;;94309:22:::1;94327:4:::0;94255:15;94309:22:::1;:::i;:::-;94208:164:::0;;::::1;::::0;;::::1;::::0;;;94174:199;;::::1;::::0;;::::1;::::0;;-1:-1:-1;94174:199:0;;;;;;;;::::1;::::0;;::::1;;::::0;;;;;::::1;::::0;;;::::1;::::0;;;;::::1;::::0;::::1;::::0;::::1;::::0;::::1;::::0;::::1;::::0;::::1;::::0;::::1;::::0;::::1;::::0;::::1;::::0;;::::1;::::0;::::1;::::0;;::::1;::::0;94417:23:::1;:36:::0;;94444:9;;-1:-1:-1;94417:36:0::1;::::0;94444:9;;94417:36:::1;:::i;:::-;::::0;;;-1:-1:-1;;94464:33:0::1;::::0;::::1;;::::0;;;:17:::1;:33;::::0;;;;:46;;94501:9;;94464:33;:46:::1;::::0;94501:9;;94464:46:::1;:::i;:::-;::::0;;;-1:-1:-1;;94556:41:0::1;::::0;;::::1;94536:17;94556:41:::0;;;:25:::1;:41;::::0;;;;;::::1;94616:23:::0;;94612:70:::1;;94641:28;::::0;::::1;;::::0;;;:17:::1;:28:::0;;;;;:41;;94673:9;;94641:28;:41:::1;::::0;94673:9;;94641:41:::1;:::i;:::-;::::0;;;-1:-1:-1;;94612:70:0::1;94521:173;94780:46;94804:14;94820:5;94780:23;:46::i;:::-;94844:68;::::0;;18941:25:1;;;18997:2;18982:18;;18975:34;;;19025:18;;;19018:34;;;94844:68:0::1;19088:55:1::0;;;19083:2;19068:18;;19061:83;94844:68:0;::::1;::::0;::::1;::::0;18928:3:1;18913:19;94844:68:0::1;;;;;;;93426:1494;;93192:1728:::0;;;;;;;:::o;55312:133::-;55371:7;55398:39;55407:15;55424:12;;55398:8;:39::i;:::-;55391:46;;55312:133;:::o;38700:361::-;38895:45;;;38884:10;16035:55:1;;;38895:45:0;;;16017:74:1;16107:18;;;;16100:34;;;38895:45:0;;;;;;;;;;15990:18:1;;;;38895:45:0;;;;;;;;;;;;;38884:57;;-1:-1:-1;;;;38884:10:0;;;;:57;;38895:45;38884:57;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;38848:93;;;;38960:7;:57;;;;-1:-1:-1;38972:11:0;;:16;;:44;;;39003:4;38992:24;;;;;;;;;;;;:::i;:::-;38952:101;;;;;;;20149:2:1;38952:101:0;;;20131:21:1;20188:2;20168:18;;;20161:30;20227:33;20207:18;;;20200:61;20278:18;;38952:101:0;19947:355:1;38952:101:0;38770:291;;38700:361;;;:::o;64351:1525::-;64541:8;64537:46;;;64565:6;:4;:6::i;:::-;64607:21;;;;64603:1266;;64821:27;64867:28;64914:27;64959:30;64981:7;64959:21;:30::i;:::-;64799:190;;;;;;65051:20;65063:7;65051:11;:20::i;:::-;65147:31;;;;;;;:22;:31;;;;;:54;;;65288:42;;;65284:572;;65351:19;65373:41;65395:19;65373;:41;:::i;:::-;65351:63;;65483:11;65458:22;;:36;;;;:::i;:::-;65433:22;:61;65542:33;65564:11;65542:19;:33;:::i;:::-;65513:26;;;;;;;:17;:26;;;;;:62;-1:-1:-1;65284:572:0;;;65616:19;65638:41;65660:19;65638;:41;:::i;:::-;65616:63;;65748:11;65723:22;;:36;;;;:::i;:::-;65698:22;:61;65807:33;65829:11;65807:19;:33;:::i;:::-;65778:26;;;;;;;:17;:26;;;;;:62;-1:-1:-1;64630:1239:0;;;64351:1525;;:::o;90679:508::-;90761:31;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;90761:31:0;90794:15;;90822:280;90846:28;;;;;;;:12;:28;;;;;:35;90842:39;;90822:280;;;90917:28;;;;;;;:12;:28;;;;;:31;;90946:1;;90917:31;;;;;;:::i;:::-;;;;;;;;;;;:38;;;90907:6;:48;90903:188;;;90990:28;;;;;;;:12;:28;;;;;:31;;91019:1;;90990:31;;;;;;:::i;:::-;;;;;;;;;;;90975:46;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;91050:1;91040:11;;91070:5;;90903:188;90883:3;;;;:::i;:::-;;;;90822:280;;;-1:-1:-1;91120:19:0;;:29;;91112:57;;;;;;;20509:2:1;91112:57:0;;;20491:21:1;20548:2;20528:18;;;20521:30;20587:17;20567:18;;;20560:45;20622:18;;91112:57:0;20307:339:1;91112:57:0;90679:508;;;;;:::o;39069:402::-;39294:51;;;39283:10;20932:15:1;;;39294:51:0;;;20914:34:1;20984:15;;;20964:18;;;20957:43;21016:18;;;;21009:34;;;39294:51:0;;;;;;;;;;20826:18:1;;;;39294:51:0;;;;;;;;;;;;;39283:63;;-1:-1:-1;;;;39283:10:0;;;;:63;;39294:51;39283:63;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;39247:99;;;;39365:7;:57;;;;-1:-1:-1;39377:11:0;;:16;;:44;;;39408:4;39397:24;;;;;;;;;;;;:::i;:::-;39357:106;;;;;;;21256:2:1;39357:106:0;;;21238:21:1;21295:2;21275:18;;;21268:30;21334:34;21314:18;;;21307:62;21405:6;21385:18;;;21378:34;21429:19;;39357:106:0;21054:400:1;39357:106:0;39157:314;;39069:402;;;;:::o;67108:767::-;67232:31;67207:8;67217:4;53199:42;53223:7;53232:8;53199:23;:42::i;:::-;67367:12:::1;:19:::0;67353:34:::1;::::0;::::1;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;-1:-1:-1;67353:34:0::1;;67336:51;;67405:9;67400:255;67424:12;:19:::0;67420:23;::::1;67400:255;;;67485:17;::::0;::::1;;::::0;;;:7:::1;:17;::::0;;;;;;;:20;;;;;;;;;67465:17;;:14;;67503:1;;67465:17;::::1;;;;;:::i;:::-;;::::0;;::::1;::::0;;;;;;:40;;;;67520:17:::1;::::0;::::1;67543:1;67520:17:::0;;;:7:::1;:17:::0;;;;;;:20;;;;;;;;;:24;67587:12:::1;:15:::0;;67559:84:::1;::::0;67587:12;67538:1;;67587:15;::::1;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;67604:19;67625:14;67640:1;67625:17;;;;;;;;:::i;:::-;;;;;;;67559:27;:84::i;:::-;67445:3:::0;::::1;::::0;::::1;:::i;:::-;;;;67400:255;;;;-1:-1:-1::0;;67820:29:0::1;::::0;;::::1;;::::0;;;:19:::1;:29;::::0;;;;67852:15:::1;67820:47:::0;;-1:-1:-1;67108:767:0;:::o;95534:1585::-;95745:47;95756:14;95772:19;95745:10;:47::i;:::-;;95846:28;95876:21;95901:33;95911:14;95927:6;95901:9;:33::i;:::-;95845:89;;;;95972:9;:26;;;95953:15;:45;;:71;;;-1:-1:-1;96002:14:0;;;;:22;;:14;:22;95953:71;:110;;;-1:-1:-1;96044:10:0;96028:27;;;;:15;:27;;;;;;;;:35;;:27;:35;95953:110;95945:145;;;;;;;21661:2:1;95945:145:0;;;21643:21:1;21700:2;21680:18;;;21673:30;21739:24;21719:18;;;21712:52;21781:18;;95945:145:0;21459:346:1;95945:145:0;96121:19;;;;96157:13;;96153:959;;96274:9;96248:23;;:35;;;;:::i;:::-;96222:23;:61;96334:33;;;;;;;:17;:33;;;;;;:45;;96370:9;;96334:45;:::i;:::-;96298:33;;;;;;;;:17;:33;;;;;;;;:81;;;;96433:25;:41;;;;;;;;96497:23;;96493:70;;96522:28;;;;;;;:17;:28;;;;;:41;;96554:9;;96522:28;:41;;96554:9;;96522:41;:::i;:::-;;;;-1:-1:-1;;96493:70:0;-1:-1:-1;96650:28:0;;;;;;;:12;:28;;;;;:43;;96679:13;;96650:43;;;;;;:::i;:::-;;;;;;;;;;;;;;96643:50;;;;;;;;;;;;;;;;;;;;;;;;;;;;;96822:12;;;:53;;;;;:12;16035:55:1;;;96822:53:0;;;16017:74:1;;;;16107:18;;;16100:34;;;96822:12:0;;;;;;;:21;;15990:18:1;;96822:53:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;96962:46;96986:14;97002:5;96962:23;:46::i;:::-;97030:70;;;22012:25:1;;;22068:2;22053:18;;22046:34;;;97030:70:0;22116:55:1;;;22096:18;;;22089:83;97030:70:0;;;;;;;;;;;22000:2:1;97030:70:0;;;95671:1448;;;95534:1585;;;:::o;67962:1738::-;68083:9;68078:327;68102:18;:25;68098:29;;68078:327;;;68149:34;68186:18;68205:1;68186:21;;;;;;;;:::i;:::-;;;;;;;;;;;;;;-1:-1:-1;68226:40:0;;68222:172;;68287:91;;;;;68372:4;68287:91;;;3968:74:1;68287:76:0;;;;;;3941:18:1;;68287:91:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;68222:172;-1:-1:-1;68129:3:0;;;;:::i;:::-;;;;68078:327;;;;68765:27;50738:6;68821:12;;68803:15;:30;;;;:::i;:::-;68795:57;;;;:::i;:::-;68765:87;;68991:9;68986:283;69010:12;:19;69006:23;;68986:283;;;69131:12;69144:1;69131:15;;;;;;;;:::i;:::-;;;;;;;;;;;69125:47;;;;;69166:4;69125:47;;;3968:74:1;69131:15:0;;;;;69125:32;;3941:18:1;;69125:47:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;69096:23;:19;69118:1;69096:23;:::i;:::-;50738:6;69060:14;69072:1;69060:11;:14::i;:::-;:32;;;;:::i;:::-;:60;;;;:::i;:::-;69059:113;;69238:12;69251:1;69238:15;;;;;;;;:::i;:::-;;;;;;;;;;;;69181:73;;;22675:34:1;69181:73:0;;;22663:47:1;;;;22740:6;22726:12;;;22719:28;22785:2;22781:15;;;22763:12;;;22756:110;22882:12;;69181:73:0;;;;;;;;;;;;69051:206;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;69031:3:0;;;;:::i;:::-;;;;68986:283;;;-1:-1:-1;50738:6:0;69481:23;:19;69503:1;69481:23;:::i;:::-;69480:43;;;;:::i;:::-;69464:12;;:60;;;;:::i;:::-;69449:12;:75;69577:29;:27;:29::i;:::-;69676:16;:14;:16::i;:::-;69658:15;:34;-1:-1:-1;67962:1738:0:o;69708:435::-;69795:34;69832:17;:15;:17::i;:::-;69795:54;;69912:9;69907:133;69931:21;:28;69927:32;;69907:133;;;70008:17;70026:1;70008:20;;;;;;;;:::i;:::-;;;;;;;69981:21;70003:1;69981:24;;;;;;;;:::i;:::-;;;;;;;;;;:47;69961:3;;;;:::i;:::-;;;;69907:133;;;;70109:26;:24;:26::i;:::-;70092:14;:43;-1:-1:-1;69708:435:0:o;65884:585::-;65946:21;;;;65942:520;;66023:27;66053:15;66060:7;66053:6;:15::i;:::-;66023:45;;66131:9;66126:118;66150:10;:17;66146:1;:21;66126:118;;;66215:10;66226:1;66215:13;;;;;;;;:::i;:::-;;;;;;;;;;;;66193:16;;;;;;;:7;:16;;;;;;:19;;;;;;;;;;:35;66210:1;66169:3;66210:1;66169:3;:::i;:::-;;;;66126:118;;;;66311:9;66306:145;66330:10;:17;66326:1;:21;66306:145;;;66411:21;66433:1;66411:24;;;;;;;;:::i;:::-;;;;;;;;;;;;;66373:32;;;;;:23;:32;;;;;;:35;;;;;;;;:62;66406:1;66349:3;66406:1;66349:3;:::i;:::-;;;;66306:145;;14:196:1;82:20;;142:42;131:54;;121:65;;111:93;;200:1;197;190:12;111:93;14:196;;;:::o;215:186::-;274:6;327:2;315:9;306:7;302:23;298:32;295:52;;;343:1;340;333:12;295:52;366:29;385:9;366:29;:::i;406:632::-;577:2;629:21;;;699:13;;602:18;;;721:22;;;548:4;;577:2;800:15;;;;774:2;759:18;;;548:4;843:169;857:6;854:1;851:13;843:169;;;918:13;;906:26;;987:15;;;;952:12;;;;879:1;872:9;843:169;;;-1:-1:-1;1029:3:1;;406:632;-1:-1:-1;;;;;;406:632:1:o;1043:180::-;1102:6;1155:2;1143:9;1134:7;1130:23;1126:32;1123:52;;;1171:1;1168;1161:12;1123:52;-1:-1:-1;1194:23:1;;1043:180;-1:-1:-1;1043:180:1:o;1410:681::-;1581:2;1633:21;;;1703:13;;1606:18;;;1725:22;;;1552:4;;1581:2;1804:15;;;;1778:2;1763:18;;;1552:4;1847:218;1861:6;1858:1;1855:13;1847:218;;;1926:13;;1941:42;1922:62;1910:75;;2040:15;;;;2005:12;;;;1883:1;1876:9;1847:218;;2096:248;2164:6;2172;2225:2;2213:9;2204:7;2200:23;2196:32;2193:52;;;2241:1;2238;2231:12;2193:52;-1:-1:-1;;2264:23:1;;;2334:2;2319:18;;;2306:32;;-1:-1:-1;2096:248:1:o;2349:1011::-;2578:2;2630:21;;;2700:13;;2603:18;;;2722:22;;;2549:4;;2578:2;2763;;2781:18;;;;2822:15;;;2549:4;2865:469;2879:6;2876:1;2873:13;2865:469;;;2938:13;;2976:9;;2964:22;;3026:11;;;3020:18;3006:12;;;2999:40;3079:11;;;3073:18;3059:12;;;3052:40;3115:4;3159:11;;;3153:18;3139:12;;;3132:40;3195:4;3239:11;;;3233:18;3219:12;;;3212:40;3281:4;3272:14;;;;3309:15;;;;2901:1;2894:9;2865:469;;;-1:-1:-1;3351:3:1;;2349:1011;-1:-1:-1;;;;;;;2349:1011:1:o;3365:260::-;3433:6;3441;3494:2;3482:9;3473:7;3469:23;3465:32;3462:52;;;3510:1;3507;3500:12;3462:52;3533:29;3552:9;3533:29;:::i;:::-;3523:39;;3581:38;3615:2;3604:9;3600:18;3581:38;:::i;:::-;3571:48;;3365:260;;;;;:::o;4053:391::-;4139:6;4147;4155;4163;4216:3;4204:9;4195:7;4191:23;4187:33;4184:53;;;4233:1;4230;4223:12;4184:53;4256:29;4275:9;4256:29;:::i;:::-;4246:39;4332:2;4317:18;;4304:32;;-1:-1:-1;4383:2:1;4368:18;;4355:32;;4434:2;4419:18;4406:32;;-1:-1:-1;4053:391:1;-1:-1:-1;;;4053:391:1:o;4695:254::-;4763:6;4771;4824:2;4812:9;4803:7;4799:23;4795:32;4792:52;;;4840:1;4837;4830:12;4792:52;4863:29;4882:9;4863:29;:::i;:::-;4853:39;4939:2;4924:18;;;;4911:32;;-1:-1:-1;;;4695:254:1:o;5999:118::-;6085:5;6078:13;6071:21;6064:5;6061:32;6051:60;;6107:1;6104;6097:12;6122:511;6190:6;6198;6206;6259:2;6247:9;6238:7;6234:23;6230:32;6227:52;;;6275:1;6272;6265:12;6227:52;6314:9;6301:23;6333:28;6355:5;6333:28;:::i;:::-;6380:5;-1:-1:-1;6437:2:1;6422:18;;6409:32;6450:30;6409:32;6450:30;:::i;:::-;6499:7;-1:-1:-1;6558:2:1;6543:18;;6530:32;6571:30;6530:32;6571:30;:::i;:::-;6620:7;6610:17;;;6122:511;;;;;:::o;6638:403::-;6724:6;6732;6740;6748;6801:3;6789:9;6780:7;6776:23;6772:33;6769:53;;;6818:1;6815;6808:12;6769:53;6841:29;6860:9;6841:29;:::i;:::-;6831:39;;6917:2;6906:9;6902:18;6889:32;6879:42;;6940:38;6974:2;6963:9;6959:18;6940:38;:::i;:::-;6930:48;;6997:38;7031:2;7020:9;7016:18;6997:38;:::i;:::-;6987:48;;6638:403;;;;;;;:::o;7046:254::-;7114:6;7122;7175:2;7163:9;7154:7;7150:23;7146:32;7143:52;;;7191:1;7188;7181:12;7143:52;7227:9;7214:23;7204:33;;7256:38;7290:2;7279:9;7275:18;7256:38;:::i;7564:241::-;7620:6;7673:2;7661:9;7652:7;7648:23;7644:32;7641:52;;;7689:1;7686;7679:12;7641:52;7728:9;7715:23;7747:28;7769:5;7747:28;:::i;7810:184::-;7862:77;7859:1;7852:88;7959:4;7956:1;7949:15;7983:4;7980:1;7973:15;7999:915;8081:6;8134:3;8122:9;8113:7;8109:23;8105:33;8102:53;;;8151:1;8148;8141:12;8102:53;8200:7;8193:4;8182:9;8178:20;8174:34;8164:62;;8222:1;8219;8212:12;8164:62;8255:2;8249:9;8297:3;8289:6;8285:16;8367:6;8355:10;8352:22;8331:18;8319:10;8316:34;8313:62;8310:242;;;8408:77;8405:1;8398:88;8509:4;8506:1;8499:15;8537:4;8534:1;8527:15;8310:242;8568:2;8561:22;8603:6;8647:3;8632:19;;8663;;;8660:39;;;8695:1;8692;8685:12;8660:39;8719:9;8737:146;8753:6;8748:3;8745:15;8737:146;;;8821:17;;8809:30;;8868:4;8859:14;;;;8770;8737:146;;;-1:-1:-1;8902:6:1;;7999:915;-1:-1:-1;;;;;7999:915:1:o;8919:184::-;8971:77;8968:1;8961:88;9068:4;9065:1;9058:15;9092:4;9089:1;9082:15;9108:184;9160:77;9157:1;9150:88;9257:4;9254:1;9247:15;9281:4;9278:1;9271:15;9297:125;9337:4;9365:1;9362;9359:8;9356:34;;;9370:18;;:::i;:::-;-1:-1:-1;9407:9:1;;9297:125::o;9427:228::-;9467:7;9593:1;9525:66;9521:74;9518:1;9515:81;9510:1;9503:9;9496:17;9492:105;9489:131;;;9600:18;;:::i;:::-;-1:-1:-1;9640:9:1;;9427:228::o;9660:274::-;9700:1;9726;9716:189;;9761:77;9758:1;9751:88;9862:4;9859:1;9852:15;9890:4;9887:1;9880:15;9716:189;-1:-1:-1;9919:9:1;;9660:274::o;9939:128::-;9979:3;10010:1;10006:6;10003:1;10000:13;9997:39;;;10016:18;;:::i;:::-;-1:-1:-1;10052:9:1;;9939:128::o;10072:195::-;10111:3;10142:66;10135:5;10132:77;10129:103;;;10212:18;;:::i;:::-;-1:-1:-1;10259:1:1;10248:13;;10072:195::o;11748:184::-;11818:6;11871:2;11859:9;11850:7;11846:23;11842:32;11839:52;;;11887:1;11884;11877:12;11839:52;-1:-1:-1;11910:16:1;;11748:184;-1:-1:-1;11748:184:1:o;19155:258::-;19227:1;19237:113;19251:6;19248:1;19245:13;19237:113;;;19327:11;;;19321:18;19308:11;;;19301:39;19273:2;19266:10;19237:113;;;19368:6;19365:1;19362:13;19359:48;;;-1:-1:-1;;19403:1:1;19385:16;;19378:27;19155:258::o;19418:274::-;19547:3;19585:6;19579:13;19601:53;19647:6;19642:3;19635:4;19627:6;19623:17;19601:53;:::i;:::-;19670:16;;;;;19418:274;-1:-1:-1;;19418:274:1:o;19697:245::-;19764:6;19817:2;19805:9;19796:7;19792:23;19788:32;19785:52;;;19833:1;19830;19823:12;19785:52;19865:9;19859:16;19884:28;19906:5;19884:28;:::i;22183:245::-;22262:6;22270;22323:2;22311:9;22302:7;22298:23;22294:32;22291:52;;;22339:1;22336;22329:12;22291:52;-1:-1:-1;;22362:16:1;;22418:2;22403:18;;;22397:25;22362:16;;22397:25;;-1:-1:-1;22183:245:1:o;22905:442::-;23054:2;23043:9;23036:21;23017:4;23086:6;23080:13;23129:6;23124:2;23113:9;23109:18;23102:34;23145:66;23204:6;23199:2;23188:9;23184:18;23179:2;23171:6;23167:15;23145:66;:::i;:::-;23263:2;23251:15;23268:66;23247:88;23232:104;;;;23338:2;23228:113;;22905:442;-1:-1:-1;;22905:442:1:o
Swarm Source
ipfs://5efa6d08b2eb70ca21abb4b800afe279cbd5aa94eedb9e5c5b96bc1201312def
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.