Source Code
Latest 25 from a total of 540 transactions
| Transaction Hash |
Method
|
Block
|
From
|
|
To
|
||||
|---|---|---|---|---|---|---|---|---|---|
| Sync | 24407611 | 14 days ago | IN | 0 ETH | 0.00001226 | ||||
| Get Reward | 24257081 | 35 days ago | IN | 0 ETH | 0.00001051 | ||||
| Get Reward | 23684274 | 116 days ago | IN | 0 ETH | 0.00053011 | ||||
| Withdraw Locked | 23684273 | 116 days ago | IN | 0 ETH | 0.00108878 | ||||
| Withdraw Locked | 23203880 | 183 days ago | IN | 0 ETH | 0.00041766 | ||||
| Get Reward | 23203868 | 183 days ago | IN | 0 ETH | 0.00049808 | ||||
| Withdraw Locked | 22871158 | 229 days ago | IN | 0 ETH | 0.00068979 | ||||
| Get Reward | 22871145 | 229 days ago | IN | 0 ETH | 0.00077812 | ||||
| Withdraw Locked | 22511481 | 279 days ago | IN | 0 ETH | 0.00081756 | ||||
| Withdraw Locked | 22465028 | 286 days ago | IN | 0 ETH | 0.00063995 | ||||
| Get Reward | 22465011 | 286 days ago | IN | 0 ETH | 0.00064501 | ||||
| Withdraw Locked | 22284338 | 311 days ago | IN | 0 ETH | 0.0002781 | ||||
| Get Reward | 22284333 | 311 days ago | IN | 0 ETH | 0.00032213 | ||||
| Withdraw Locked | 22038555 | 346 days ago | IN | 0 ETH | 0.00062698 | ||||
| Get Reward | 22038552 | 346 days ago | IN | 0 ETH | 0.00053936 | ||||
| Withdraw Locked | 22036776 | 346 days ago | IN | 0 ETH | 0.00037426 | ||||
| Get Reward | 22031739 | 347 days ago | IN | 0 ETH | 0.00032411 | ||||
| Get Reward | 21955593 | 357 days ago | IN | 0 ETH | 0.00043201 | ||||
| Get Reward | 21880887 | 368 days ago | IN | 0 ETH | 0.00049573 | ||||
| Withdraw Locked | 21833891 | 374 days ago | IN | 0 ETH | 0.00064806 | ||||
| Stake Locked | 21754997 | 385 days ago | IN | 0 ETH | 0.0029558 | ||||
| Withdraw Locked | 21642989 | 401 days ago | IN | 0 ETH | 0.00186118 | ||||
| Get Reward | 21642692 | 401 days ago | IN | 0 ETH | 0.00170334 | ||||
| Withdraw Locked | 21635705 | 402 days ago | IN | 0 ETH | 0.00086604 | ||||
| Get Reward | 21635683 | 402 days ago | IN | 0 ETH | 0.00113234 |
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Loading...
Loading
Cross-Chain Transactions
Loading...
Loading
Contract Name:
FraxUnifiedFarm_ERC20_Fraxswap_FRAX_FPIS
Compiler Version
v0.8.15+commit.e14f2714
Contract Source Code (Solidity)
/**
*Submitted for verification at Etherscan.io on 2022-08-23
*/
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.8.0;
// Sources flattened with hardhat v2.10.1 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/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/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/Misc_AMOs/convex/IConvexBaseRewardPool.sol
interface IConvexBaseRewardPool {
function addExtraReward(address _reward) external returns (bool);
function balanceOf(address account) external view returns (uint256);
function clearExtraRewards() external;
function currentRewards() external view returns (uint256);
function donate(uint256 _amount) external returns (bool);
function duration() external view returns (uint256);
function earned(address account) external view returns (uint256);
function extraRewards(uint256) external view returns (address);
function extraRewardsLength() external view returns (uint256);
function getReward() external returns (bool);
function getReward(address _account, bool _claimExtras) external returns (bool);
function historicalRewards() external view returns (uint256);
function lastTimeRewardApplicable() external view returns (uint256);
function lastUpdateTime() external view returns (uint256);
function newRewardRatio() external view returns (uint256);
function operator() external view returns (address);
function periodFinish() external view returns (uint256);
function pid() external view returns (uint256);
function queueNewRewards(uint256 _rewards) external returns (bool);
function queuedRewards() external view returns (uint256);
function rewardManager() external view returns (address);
function rewardPerToken() external view returns (uint256);
function rewardPerTokenStored() external view returns (uint256);
function rewardRate() external view returns (uint256);
function rewardToken() external view returns (address);
function rewards(address) external view returns (uint256);
function stake(uint256 _amount) external returns (bool);
function stakeAll() external returns (bool);
function stakeFor(address _for, uint256 _amount) external returns (bool);
function stakingToken() external view returns (address);
function totalSupply() external view returns (uint256);
function userRewardPerTokenPaid(address) external view returns (uint256);
function withdraw(uint256 amount, bool claim) external returns (bool);
function withdrawAll(bool claim) external;
function withdrawAllAndUnwrap(bool claim) external;
function withdrawAndUnwrap(uint256 amount, bool claim) external returns (bool);
}
// File contracts/Staking/FraxUnifiedFarmTemplate.sol
// ====================================================================
// | ______ _______ |
// | / _____________ __ __ / ____(_____ ____ _____ ________ |
// | / /_ / ___/ __ `| |/_/ / /_ / / __ \/ __ `/ __ \/ ___/ _ \ |
// | / __/ / / / /_/ _> < / __/ / / / / / /_/ / / / / /__/ __/ |
// | /_/ /_/ \__,_/_/|_| /_/ /_/_/ /_/\__,_/_/ /_/\___/\___/ |
// | |
// ====================================================================
// ====================== FraxUnifiedFarmTemplate =====================
// ====================================================================
// 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
// 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
// Extra rewards
contract FraxUnifiedFarmTemplate is Owned, ReentrancyGuard {
/* ========== STATE VARIABLES ========== */
// Instances
IveFXS private immutable veFXS = IveFXS(0xc8418aF6358FFddA74e09Ca9CC3Fe03Ca6aDC5b0);
// Frax related
address internal immutable frax_address = 0x853d955aCEf822Db058eb8505911ED77F175b99e;
uint256 public 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(2e18); // E18. 1x = e18
uint256 public lock_time_for_max_multiplier = 1 * 365 * 86400; // 1 year
// uint256 public lock_time_for_max_multiplier = 2 * 86400; // 2 days
uint256 public lock_time_min = 594000; // 6.875 * 86400 (~7 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(4e18); // 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) public 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
// Stakers set which proxy(s) they want to use
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 and overrides
bool public stakesUnlocked; // Release locked stakes in case of emergency
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 updateRewardAndBalanceMdf(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
// )
// ) ;
return Math.min(
lock_max_multiplier,
(secs * lock_max_multiplier) / 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 getProxyFor(address addr) public view returns (address){
if (valid_vefxs_proxies[addr]) {
// If addr itself is a proxy, return that.
// If it farms itself directly, it should use the shared LP tally in proxyStakedFrax
return addr;
}
else {
// Otherwise, return the proxy, or address(0)
return staker_designated_proxies[addr];
}
}
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 = getProxyFor(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 =============== */
// Proxy can allow a staker to use their veFXS balance (the staker will have to reciprocally toggle them too)
// Must come before stakerSetVeFXSProxy
// CALLED BY PROXY
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)
// CALLED BY STAKER
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");
// Corner case sanity check to make sure LP isn't double counted
address old_proxy_addr = staker_designated_proxies[msg.sender];
if (old_proxy_addr != address(0)) {
// Remove the LP count from the old proxy
proxy_lp_balances[old_proxy_addr] -= _locked_liquidity[msg.sender];
}
// Set the new proxy
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) public {
// 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 destination_address) public nonReentrant {
require(rewardsCollectionPaused == false, "Rewards collection paused");
return _getRewardExtraLogic(msg.sender, destination_address);
}
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
// For backwards-compatibility
function getReward(address destination_address) external nonReentrant returns (uint256[] memory) {
return _getReward(msg.sender, destination_address, true);
}
function getReward2(address destination_address, bool claim_extra_too) external nonReentrant returns (uint256[] memory) {
return _getReward(msg.sender, destination_address, claim_extra_too);
}
// No withdrawer == msg.sender check needed since this is only internally callable
function _getReward(address rewardee, address destination_address, bool do_extra_logic) internal updateRewardAndBalanceMdf(rewardee, true) returns (uint256[] memory rewards_before) {
// Update the last reward claim time first, as an extra reentrancy safeguard
lastRewardClaimTime[rewardee] = block.timestamp;
// Make sure rewards collection isn't paused
require(rewardsCollectionPaused == false, "Rewards collection paused");
// 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;
if (rewards_before[i] > 0) {
TransferHelper.safeTransfer(rewardTokens[i], destination_address, rewards_before[i]);
emit RewardPaid(rewardee, rewards_before[i], rewardTokens[i], destination_address);
}
}
// Handle additional reward logic
if (do_extra_logic) {
_getRewardExtraLogic(rewardee, destination_address);
}
}
// ------ 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)) <= IERC20(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();
// Pull in rewards and set the reward rate for one week, based off of that
// If the rewards get messed up for some reason, set this to 0 and it will skip
// if (rewardRatesManual[1] != 0 && rewardRatesManual[2] != 0) {
// // CRV & CVX
// // ====================================
// uint256 crv_before = ERC20(rewardTokens[1]).balanceOf(address(this));
// uint256 cvx_before = ERC20(rewardTokens[2]).balanceOf(address(this));
// IConvexBaseRewardPool(0x329cb014b562d5d42927cfF0dEdF4c13ab0442EF).getReward(
// address(this),
// true
// );
// uint256 crv_after = ERC20(rewardTokens[1]).balanceOf(address(this));
// uint256 cvx_after = ERC20(rewardTokens[2]).balanceOf(address(this));
// // Set the new reward rate
// rewardRatesManual[1] = (crv_after - crv_before) / rewardsDuration;
// rewardRatesManual[2] = (cvx_after - cvx_before) / rewardsDuration;
// }
}
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);
// Update the fraxPerLPStored
fraxPerLPStored = fraxPerLPToken();
if (block.timestamp >= periodFinish) {
retroCatchUp();
}
else {
_updateStoredRewardsAndTime();
}
}
/* ========== RESTRICTED FUNCTIONS - Curator 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;
}
// 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;
}
/* ========== EVENTS ========== */
event RewardPaid(address indexed user, uint256 amount, address token_address, address destination_address);
/* ========== A CHICKEN ========== */
//
// ,~.
// ,-'__ `-,
// {,-' `. } ,')
// ,( a ) `-.__ ,',')~,
// <=.) ( `-.__,==' ' ' '}
// ( ) /)
// `-'\ , )
// | \ `~. /
// \ `._ \ /
// \ `._____,' ,'
// `-. ,'
// `-._ _,-'
// 77jj'
// //_||
// __//--'/`
// ,--'/` '
//
// [hjw] https://textart.io/art/vw6Sa3iwqIRGkZsN1BC2vweF/chicken
}
// File contracts/Fraxswap/core/interfaces/IUniswapV2PairV5.sol
interface IUniswapV2PairV5 {
event Approval(address indexed owner, address indexed spender, uint value);
event Transfer(address indexed from, address indexed to, uint value);
function name() external pure returns (string memory);
function symbol() external pure returns (string memory);
function decimals() external pure returns (uint8);
function totalSupply() external view returns (uint);
function balanceOf(address owner) external view returns (uint);
function allowance(address owner, address spender) external view returns (uint);
function approve(address spender, uint value) external returns (bool);
function transfer(address to, uint value) external returns (bool);
function transferFrom(address from, address to, uint value) external returns (bool);
function DOMAIN_SEPARATOR() external view returns (bytes32);
function PERMIT_TYPEHASH() external pure returns (bytes32);
function nonces(address owner) external view returns (uint);
function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external;
event Mint(address indexed sender, uint amount0, uint amount1);
event Burn(address indexed sender, uint amount0, uint amount1, address indexed to);
event Swap(
address indexed sender,
uint amount0In,
uint amount1In,
uint amount0Out,
uint amount1Out,
address indexed to
);
event Sync(uint112 reserve0, uint112 reserve1);
function MINIMUM_LIQUIDITY() external pure returns (uint);
function factory() external view returns (address);
function token0() external view returns (address);
function token1() external view returns (address);
function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast);
function price0CumulativeLast() external view returns (uint);
function price1CumulativeLast() external view returns (uint);
function kLast() external view returns (uint);
function mint(address to) external returns (uint liquidity);
function burn(address to) external returns (uint amount0, uint amount1);
function swap(uint amount0Out, uint amount1Out, address to, bytes calldata data) external;
function skim(address to) external;
function sync() external;
function initialize(address, address) external;
}
// File contracts/Fraxswap/core/interfaces/IFraxswapPair.sol
// ====================================================================
// | ______ _______ |
// | / _____________ __ __ / ____(_____ ____ _____ ________ |
// | / /_ / ___/ __ `| |/_/ / /_ / / __ \/ __ `/ __ \/ ___/ _ \ |
// | / __/ / / / /_/ _> < / __/ / / / / / /_/ / / / / /__/ __/ |
// | /_/ /_/ \__,_/_/|_| /_/ /_/_/ /_/\__,_/_/ /_/\___/\___/ |
// | |
// ====================================================================
// ========================= IFraxswapPair ==========================
// ====================================================================
// Fraxswap LP Pair Interface
// Inspired by https://www.paradigm.xyz/2021/07/twamm
// https://github.com/para-dave/twamm
// Frax Finance: https://github.com/FraxFinance
// Primary Author(s)
// Rich Gee: https://github.com/zer0blockchain
// Dennis: https://github.com/denett
// Reviewer(s) / Contributor(s)
// Travis Moore: https://github.com/FortisFortuna
// Sam Kazemian: https://github.com/samkazemian
interface IFraxswapPair is IUniswapV2PairV5 {
// TWAMM
event LongTermSwap0To1(address indexed addr, uint256 orderId, uint256 amount0In, uint256 numberOfTimeIntervals);
event LongTermSwap1To0(address indexed addr, uint256 orderId, uint256 amount1In, uint256 numberOfTimeIntervals);
event CancelLongTermOrder(address indexed addr, uint256 orderId, address sellToken, uint256 unsoldAmount, address buyToken, uint256 purchasedAmount);
event WithdrawProceedsFromLongTermOrder(address indexed addr, uint256 orderId, address indexed proceedToken, uint256 proceeds, bool orderExpired);
function fee() external view returns (uint);
function longTermSwapFrom0To1(uint256 amount0In, uint256 numberOfTimeIntervals) external returns (uint256 orderId);
function longTermSwapFrom1To0(uint256 amount1In, uint256 numberOfTimeIntervals) external returns (uint256 orderId);
function cancelLongTermSwap(uint256 orderId) external;
function withdrawProceedsFromLongTermSwap(uint256 orderId) external returns (bool is_expired, address rewardTkn, uint256 totalReward);
function executeVirtualOrders(uint256 blockTimestamp) external;
function getAmountOut(uint amountIn, address tokenIn) external view returns (uint);
function getAmountIn(uint amountOut, address tokenOut) external view returns (uint);
function orderTimeInterval() external returns (uint256);
function getTWAPHistoryLength() external view returns (uint);
function getTwammReserves() external view returns (uint112 _reserve0, uint112 _reserve1, uint32 _blockTimestampLast, uint112 _twammReserve0, uint112 _twammReserve1, uint256 _fee);
function getReserveAfterTwamm(uint256 blockTimestamp) external view returns (uint112 _reserve0, uint112 _reserve1, uint256 lastVirtualOrderTimestamp, uint112 _twammReserve0, uint112 _twammReserve1);
function getNextOrderID() external view returns (uint256);
function getOrderIDsForUser(address user) external view returns (uint256[] memory);
function getOrderIDsForUserLength(address user) external view returns (uint256);
// function getDetailedOrdersForUser(address user, uint256 offset, uint256 limit) external view returns (LongTermOrdersLib.Order[] memory detailed_orders);
function twammUpToDate() external view returns (bool);
function getTwammState() external view returns (uint256 token0Rate, uint256 token1Rate, uint256 lastVirtualOrderTimestamp, uint256 orderTimeInterval_rtn, uint256 rewardFactorPool0, uint256 rewardFactorPool1);
function getTwammSalesRateEnding(uint256 _blockTimestamp) external view returns (uint256 orderPool0SalesRateEnding, uint256 orderPool1SalesRateEnding);
function getTwammRewardFactor(uint256 _blockTimestamp) external view returns (uint256 rewardFactorPool0AtTimestamp, uint256 rewardFactorPool1AtTimestamp);
function getTwammOrder(uint256 orderId) external view returns (uint256 id, uint256 creationTimestamp, uint256 expirationTimestamp, uint256 saleRate, address owner, address sellTokenAddr, address buyTokenAddr);
function getTwammOrderProceedsView(uint256 orderId, uint256 blockTimestamp) external view returns (bool orderExpired, uint256 totalReward);
function getTwammOrderProceeds(uint256 orderId) external returns (bool orderExpired, uint256 totalReward);
function togglePauseNewSwaps() external;
}
// File contracts/Staking/FraxUnifiedFarm_ERC20.sol
// ====================================================================
// | ______ _______ |
// | / _____________ __ __ / ____(_____ ____ _____ ________ |
// | / /_ / ___/ __ `| |/_/ / /_ / / __ \/ __ `/ __ \/ ___/ _ \ |
// | / __/ / / / /_/ _> < / __/ / / / / / /_/ / / / / /__/ __/ |
// | /_/ /_/ \__,_/_/|_| /_/ /_/_/ /_/\__,_/_/ /_/\___/\___/ |
// | |
// ====================================================================
// ======================= FraxUnifiedFarm_ERC20 ======================
// ====================================================================
// For ERC20 Tokens
// Uses FraxUnifiedFarmTemplate.sol
// -------------------- VARIES --------------------
// Convex wrappers
// import "../Misc_AMOs/convex/IConvexStakingWrapperFrax.sol";
// import "../Misc_AMOs/convex/IDepositToken.sol";
// import "../Misc_AMOs/curve/I2pool.sol";
// import "../Misc_AMOs/curve/I2poolToken.sol";
// Fraxswap
// 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
// import '../Misc_AMOs/vesper/IVPool.sol';
// ------------------------------------------------
contract FraxUnifiedFarm_ERC20 is FraxUnifiedFarmTemplate {
/* ========== STATE VARIABLES ========== */
// -------------------- COMMON --------------------
bool internal frax_is_token0;
// -------------------- VARIES --------------------
// Convex stkcvxFPIFRAX, stkcvxFRAXBP, etc
// IConvexStakingWrapperFrax public immutable stakingToken;
// I2poolToken public immutable curveToken;
// I2pool public immutable curvePool;
// Fraxswap
IFraxswapPair public immutable stakingToken;
// G-UNI
// IGUniPool public immutable stakingToken;
// mStable
// IFeederPool public immutable stakingToken;
// sdETH-FraxPut Vault
// IOpynPerpVault public immutable stakingToken;
// StakeDAO Vault
// IStakeDaoVault public immutable stakingToken;
// Uniswap V2
// IUniswapV2Pair public immutable stakingToken;
// Vesper
// IVPool public immutable 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 --------------------
// Convex stkcvxFPIFRAX and stkcvxFRAXBP only
// stakingToken = IConvexStakingWrapperFrax(_stakingToken);
// curveToken = I2poolToken(stakingToken.curveToken());
// curvePool = I2pool(curveToken.minter());
// address token0 = curvePool.coins(0);
// frax_is_token0 = (token0 == frax_address);
// Convex stkcvxBUSDBP and other metaFRAXBPs, where the token is also the pool
// stakingToken = IConvexStakingWrapperFrax(_stakingToken);
// curveToken = I2poolToken(stakingToken.curveToken());
// curvePool = I2pool(address(curveToken));
// frax_is_token0 = false; // Irrelevant here, as token 0 will be FRAXBP
// Fraxswap
stakingToken = IFraxswapPair(_stakingToken);
address token0 = stakingToken.token0();
frax_is_token0 = (token0 == frax_address);
// 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;
// Convex stkcvxFPIFRAX and stkcvxFRAXBP only
// ============================================
// {
// // Half of the LP is FRAXBP
// // Using 0.5 * virtual price for gas savings
// frax_per_lp_token = curvePool.get_virtual_price() / 2;
// }
// Convex stkcvxBUSDBP and other metaFRAXBPs
// ============================================
// {
// // Half of the LP is FRAXBP. Half of that should be FRAX.
// // Using 0.25 * virtual price for gas savings
// frax_per_lp_token = curvePool.get_virtual_price() / 4;
// }
// Fraxswap
// ============================================
{
uint256 total_frax_reserves;
(uint256 _reserve0, uint256 _reserve1, , ,) = (stakingToken.getReserveAfterTwamm(block.timestamp));
if (frax_is_token0) total_frax_reserves = _reserve0;
else total_frax_reserves = _reserve1;
frax_per_lp_token = (total_frax_reserves * 1e18) / stakingToken.totalSupply();
}
// 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 ------
function calcCurrLockMultiplier(address account, uint256 stake_idx) public view returns (uint256 midpoint_lock_multiplier) {
// Get the stake
LockedStake memory thisStake = lockedStakes[account][stake_idx];
// Handles corner case where user never claims for a new stake
// Don't want the multiplier going above the max
uint256 accrue_start_time;
if (lastRewardClaimTime[account] < thisStake.start_timestamp) {
accrue_start_time = thisStake.start_timestamp;
}
else {
accrue_start_time = lastRewardClaimTime[account];
}
// 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 - accrue_start_time;
uint256 time_after_expiry = block.timestamp - thisStake.ending_timestamp;
// Average the pre-expiry lock multiplier
uint256 pre_expiry_avg_multiplier = lockMultiplier(time_before_expiry / 2);
// Get the weighted-average lock_multiplier
// uint256 numerator = (pre_expiry_avg_multiplier * time_before_expiry) + (MULTIPLIER_PRECISION * time_after_expiry);
uint256 numerator = (pre_expiry_avg_multiplier * time_before_expiry) + (0 * time_after_expiry);
midpoint_lock_multiplier = numerator / (time_before_expiry + time_after_expiry);
}
else {
// Otherwise, it needs to just be 1x
// midpoint_lock_multiplier = MULTIPLIER_PRECISION;
// Otherwise, it needs to just be 0x
midpoint_lock_multiplier = 0;
}
}
// If the lock is not expired
else {
// Decay the lock multiplier based on the time left
uint256 avg_time_left;
{
uint256 time_left_p1 = thisStake.ending_timestamp - accrue_start_time;
uint256 time_left_p2 = thisStake.ending_timestamp - block.timestamp;
avg_time_left = (time_left_p1 + time_left_p2) / 2;
}
midpoint_lock_multiplier = lockMultiplier(avg_time_left);
}
// Sanity check: make sure it never goes above the initial multiplier
if (midpoint_lock_multiplier > thisStake.lock_multiplier) midpoint_lock_multiplier = thisStake.lock_multiplier;
}
// Calculate 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) ||
(new_vefxs_multiplier >= _vefxsMultiplierStored[account])
) {
// This is only called for the first stake to make sure the veFXS multiplier is not cut in half
// Also used if the user increased or maintained their position
midpoint_vefxs_multiplier = new_vefxs_multiplier;
}
else {
// Handles natural decay with a non-increased veFXS position
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];
// Calculate the midpoint lock multiplier
uint256 midpoint_lock_multiplier = calcCurrLockMultiplier(account, i);
// Calculate the combined boost
uint256 liquidity = thisStake.liquidity;
uint256 combined_boosted_amount = liquidity + ((liquidity * (midpoint_lock_multiplier + midpoint_vefxs_multiplier)) / MULTIPLIER_PRECISION);
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) nonReentrant updateRewardAndBalanceMdf(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 positive");
// 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 = getProxyFor(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);
emit LockedAdditional(msg.sender, kek_id, addl_liq);
}
// Extends the lock of an existing stake
function lockLonger(bytes32 kek_id, uint256 new_ending_ts) nonReentrant updateRewardAndBalanceMdf(msg.sender, true) public {
// Get the stake and its index
(LockedStake memory thisStake, uint256 theArrayIndex) = _getStake(msg.sender, kek_id);
// Check
require(new_ending_ts > block.timestamp, "Must be in the future");
// Calculate some times
uint256 time_left = (thisStake.ending_timestamp > block.timestamp) ? thisStake.ending_timestamp - block.timestamp : 0;
uint256 new_secs = new_ending_ts - block.timestamp;
// Checks
// require(time_left > 0, "Already expired");
require(new_secs > time_left, "Cannot shorten lock time");
require(new_secs >= lock_time_min, "Minimum stake time not met");
require(new_secs <= lock_time_for_max_multiplier, "Trying to lock for too long");
// Update the stake
lockedStakes[msg.sender][theArrayIndex] = LockedStake(
kek_id,
block.timestamp,
thisStake.liquidity,
new_ending_ts,
lockMultiplier(new_secs)
);
// Need to call to update the combined weights
updateRewardAndBalance(msg.sender, false);
emit LockedLonger(msg.sender, kek_id, new_secs, block.timestamp, new_ending_ts);
}
// Two different stake functions are needed because of delegateCall and msg.sender issues (important for proxies)
function stakeLocked(uint256 liquidity, uint256 secs) nonReentrant external returns (bytes32) {
return _stakeLocked(msg.sender, msg.sender, liquidity, secs, block.timestamp);
}
// 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 updateRewardAndBalanceMdf(staker_address, true) returns (bytes32) {
require(stakingPaused == false, "Staking paused");
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 = getProxyFor(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);
return kek_id;
}
// ------ WITHDRAWING ------
// Two different withdrawLocked functions are needed because of delegateCall and msg.sender issues (important for proxies)
function withdrawLocked(bytes32 kek_id, address destination_address) nonReentrant external returns (uint256) {
require(withdrawalsPaused == false, "Withdrawals paused");
return _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
function _withdrawLocked(
address staker_address,
address destination_address,
bytes32 kek_id
) internal returns (uint256) {
// Collect rewards first and then update the balances
_getReward(staker_address, destination_address, true);
// Get the stake and its index
(LockedStake memory thisStake, uint256 theArrayIndex) = _getStake(staker_address, kek_id);
require(block.timestamp >= thisStake.ending_timestamp || stakesUnlocked == true, "Stake is still locked!");
uint256 liquidity = thisStake.liquidity;
if (liquidity > 0) {
// Give the tokens to the destination_address
// Should throw if insufficient balance
TransferHelper.safeTransfer(address(stakingToken), destination_address, liquidity);
// Update liquidities
_total_liquidity_locked -= liquidity;
_locked_liquidity[staker_address] -= liquidity;
{
address the_proxy = getProxyFor(staker_address);
if (the_proxy != address(0)) proxy_lp_balances[the_proxy] -= liquidity;
}
// Remove the stake from the array
delete lockedStakes[staker_address][theArrayIndex];
// Need to call again to make sure everything is correct
updateRewardAndBalance(staker_address, false);
emit WithdrawLocked(staker_address, liquidity, kek_id, destination_address);
}
return liquidity;
}
function _getRewardExtraLogic(address rewardee, address destination_address) internal override {
// Do nothing
}
/* ========== RESTRICTED FUNCTIONS - Owner or timelock only ========== */
// Inherited...
/* ========== EVENTS ========== */
event LockedAdditional(address indexed user, bytes32 kek_id, uint256 amount);
event LockedLonger(address indexed user, bytes32 kek_id, uint256 new_secs, uint256 new_start_ts, uint256 new_end_ts);
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_Fraxswap_FRAX_FPIS.sol
contract FraxUnifiedFarm_ERC20_Fraxswap_FRAX_FPIS 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
Contract ABI
API[{"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":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"bytes32","name":"kek_id","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"LockedAdditional","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"bytes32","name":"kek_id","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"new_secs","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"new_start_ts","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"new_end_ts","type":"uint256"}],"name":"LockedLonger","type":"event"},{"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":"address","name":"token_address","type":"address"},{"indexed":false,"internalType":"address","name":"destination_address","type":"address"}],"name":"RewardPaid","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":"account","type":"address"},{"internalType":"uint256","name":"stake_idx","type":"uint256"}],"name":"calcCurrLockMultiplier","outputs":[{"internalType":"uint256","name":"midpoint_lock_multiplier","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":"fraxPerLPStored","outputs":[{"internalType":"uint256","name":"","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":"addr","type":"address"}],"name":"getProxyFor","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":[{"internalType":"address","name":"destination_address","type":"address"},{"internalType":"bool","name":"claim_extra_too","type":"bool"}],"name":"getReward2","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"destination_address","type":"address"}],"name":"getRewardExtraLogic","outputs":[],"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":[{"internalType":"address","name":"","type":"address"}],"name":"lastRewardClaimTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"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":"bytes32","name":"kek_id","type":"bytes32"},{"internalType":"uint256","name":"new_ending_ts","type":"uint256"}],"name":"lockLonger","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":"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":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"proxy_address","type":"address"}],"name":"stakerSetVeFXSProxy","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 IFraxswapPair","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":[{"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"},{"internalType":"bool","name":"sync_too","type":"bool"}],"name":"updateRewardAndBalance","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":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"}]Contract Creation Code
60e060405273c8418af6358ffdda74e09ca9cc3fe03ca6adc5b060805273853d955acef822db058eb8505911ed77f175b99e60a052671bc16d674ec8000060068190556301e1338060075562091050600855673782dace9d9000006009819055600a91909155600b553480156200007557600080fd5b50604051620058523803806200585283398101604081905262000098916200062f565b86868686868686868686868686856001600160a01b038116620001015760405162461bcd60e51b815260206004820152601960248201527f4f776e657220616464726573732063616e6e6f74206265203000000000000000604482015260640160405180910390fd5b600080546001600160a01b0319166001600160a01b03831690811782556040805192835260208301919091527fb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159c910160405180910390a150600160025584516200017390601090602088019062000406565b5081516200018990601190602085019062000406565b5080516200019f90601290602084019062000406565b508251620001b590601390602086019062000470565b5060005b855181101562000320578060146000888481518110620001dd57620001dd62000736565b6020908102919091018101516001600160a01b03168252810191909152604001600090812091909155601580546001810182559082527f55f448fdea98c4d29eb340757ef0a66cd03dbb9538908a6a81d96026b71ec475015584518590829081106200024d576200024d62000736565b6020026020010151600f60008884815181106200026e576200026e62000736565b6020908102919091018101516001600160a01b03908116835290820192909252604001600090812080546001600160a01b031916939092169290921790556019805460018181019092557f944998273e477b495144fb8794c914197f3ccb46be2900f4698fd0ef743c969501829055601a8054918201815582527f057c384a7d1c54f3a1b2e5e67b2617b8224fdfd1ea7234eea573a6ff665ff63e015580620003178162000762565b915050620001b9565b506021805460ff19169055426005819055620003419062093a80906200077e565b60049081556001600160a01b03881660c081905260408051630dfe168160e01b8152905160009950919750630dfe168196508083019550602094509092508290030181865afa15801562000399573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620003bf919062000799565b905060a0516001600160a01b0316816001600160a01b031614602160046101000a81548160ff021916908315150217905550505050505050505050505050505050620007be565b8280548282559060005260206000209081019282156200045e579160200282015b828111156200045e57825182546001600160a01b0319166001600160a01b0390911617825560209092019160019091019062000427565b506200046c929150620004ae565b5090565b8280548282559060005260206000209081019282156200045e579160200282015b828111156200045e57825182559160200191906001019062000491565b5b808211156200046c5760008155600101620004af565b80516001600160a01b0381168114620004dd57600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b0381118282101715620005235762000523620004e2565b604052919050565b60006001600160401b03821115620005475762000547620004e2565b5060051b60200190565b600082601f8301126200056357600080fd5b815160206200057c62000576836200052b565b620004f8565b82815260059290921b840181019181810190868411156200059c57600080fd5b8286015b84811015620005c257620005b481620004c5565b8352918301918301620005a0565b509695505050505050565b600082601f830112620005df57600080fd5b81516020620005f262000576836200052b565b82815260059290921b840181019181810190868411156200061257600080fd5b8286015b84811015620005c2578051835291830191830162000616565b600080600080600080600060e0888a0312156200064b57600080fd5b6200065688620004c5565b60208901519097506001600160401b03808211156200067457600080fd5b620006828b838c0162000551565b975060408a01519150808211156200069957600080fd5b620006a78b838c0162000551565b965060608a0151915080821115620006be57600080fd5b620006cc8b838c01620005cd565b955060808a0151915080821115620006e357600080fd5b620006f18b838c0162000551565b945060a08a01519150808211156200070857600080fd5b50620007178a828b0162000551565b9250506200072860c08901620004c5565b905092959891949750929550565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b6000600182016200077757620007776200074c565b5060010190565b600082198211156200079457620007946200074c565b500190565b600060208284031215620007ac57600080fd5b620007b782620004c5565b9392505050565b60805160a05160c05161502f620008236000396000818161065b015281816114a2015281816115860152818161225d0152818161382d015261442e01526000505060008181610fc50152818161107a015281816110f40152612142015261502f6000f3fe608060405234801561001057600080fd5b50600436106103cf5760003560e01c80638bad86a7116101ff578063d42fc9b41161011a578063e7f30582116100ad578063f2caeb1e1161007c578063f2caeb1e14610942578063f77e34d114610955578063facefb6414610968578063fff6cae91461097b57600080fd5b8063e7f3058214610914578063ebe2b12b14610927578063f288baf614610930578063f2a8d3491461093957600080fd5b8063de1a6551116100e9578063de1a6551146108de578063e01f62bf146108f1578063e1ba95d2146108f9578063e44b9fa51461090157600080fd5b8063d42fc9b41461086f578063d5e1a9c614610882578063d7400d5614610895578063d9f96e8d146108a857600080fd5b8063c00007b011610192578063cc2abd6411610161578063cc2abd6414610837578063cdc82e801461084a578063d2010fb414610853578063d2fbdc0d1461085c57600080fd5b8063c00007b0146107d2578063c3543826146107e5578063c8f33c91146107f8578063ca6df29d1461080157600080fd5b8063a0f23476116101ce578063a0f234761461079a578063aa1d4fce146107ad578063b85efd06146107b6578063b94c4dcb146107c957600080fd5b80638bad86a71461072c5780638da5cb5b1461075a57806391cf600a1461077a5780639637927f1461078d57600080fd5b806353a47bb7116102ef57806372f702f31161028257806379ba50971161025157806379ba5097146106de5780637d6ef08e146106e65780637f472e54146107065780638980f11f1461071957600080fd5b806372f702f314610656578063774d4ae71461067d5780637910d17b146106905780637970833e146106a357600080fd5b806369339245116102be57806369339245146106055780636c430dbb146106255780636e27cef91461064557806370641a361461064e57600080fd5b806353a47bb7146105c257806355189773146105e25780635bfd9258146105f557806364f2c060146105fd57600080fd5b8063231b68dc11610367578063386a952511610336578063386a95251461055c578063387edc861461056657806341a16f3f146105795780634fd2b536146105af57600080fd5b8063231b68dc1461049657806328408bab146104b95780632c0c2a0a1461051357806336f89af21461052657600080fd5b806317b18c89116103a357806317b18c89146104485780631c1f78eb1461045b5780631e090f01146104635780631face8561461048357600080fd5b80628cc262146103d45780630d7bac4f146103fd57806312edb24c1461041e5780631627540c14610433575b600080fd5b6103e76103e23660046149a9565b610983565b6040516103f491906149c4565b60405180910390f35b61041061040b366004614a08565b610b02565b6040519081526020016103f4565b610426610b2e565b6040516103f49190614a21565b6104466104413660046149a9565b610b9d565b005b610410610456366004614a6f565b610cc2565b6103e7610d4c565b6104766104713660046149a9565b610ded565b6040516103f49190614a91565b6104106104913660046149a9565b610ea1565b6104a96104a4366004614aff565b610ee7565b60405190151581526020016103f4565b6104ee6104c73660046149a9565b602080526000908152604090205473ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016103f4565b6104106105213660046149a9565b610f55565b6104106105343660046149a9565b73ffffffffffffffffffffffffffffffffffffffff166000908152601e602052604090205490565b61041062093a8081565b6104466105743660046149a9565b611269565b6104ee6105873660046149a9565b600f6020526000908152604090205473ffffffffffffffffffffffffffffffffffffffff1681565b6104106105bd3660046149a9565b611353565b6001546104ee9073ffffffffffffffffffffffffffffffffffffffff1681565b6104466105f0366004614b40565b611374565b610410611498565b601c54610410565b6104106106133660046149a9565b60146020526000908152604090205481565b6104106106333660046149a9565b60186020526000908152604090205481565b61041060085481565b6103e7611638565b6104ee7f000000000000000000000000000000000000000000000000000000000000000081565b61041061068b366004614b77565b611797565b6103e761069e366004614b40565b6119a3565b6106b66106b1366004614b77565b611a1f565b604080519586526020860194909452928401919091526060830152608082015260a0016103f4565b610446611a6d565b6104106106f43660046149a9565b601f6020526000908152604090205481565b6104106107143660046149a9565b611bb8565b610446610727366004614b77565b611bcf565b61073f61073a3660046149a9565b611db8565b604080519384526020840192909252908201526060016103f4565b6000546104ee9073ffffffffffffffffffffffffffffffffffffffff1681565b6104466107883660046149a9565b611fec565b6021546104a99060ff1681565b6104106107a83660046149a9565b6120df565b61041060095481565b6104466107c4366004614a6f565b6121b7565b61041060075481565b6103e76107e03660046149a9565b61240e565b6104ee6107f33660046149a9565b612496565b61041060055481565b61041061080f3660046149a9565b73ffffffffffffffffffffffffffffffffffffffff1660009081526022602052604090205490565b610446610845366004614ba1565b6124f8565b61041060065481565b61041060035481565b61044661086a366004614a6f565b61262e565b61041061087d3660046149a9565b612992565b610446610890366004614bec565b6129ce565b6104466108a33660046149a9565b612bbd565b6104106108b63660046149a9565b73ffffffffffffffffffffffffffffffffffffffff166000908152601d602052604090205490565b6104466108ec366004614aff565b612dd8565b601b54610410565b610446612ebf565b61041061090f366004614c39565b612f90565b6104466109223660046149a9565b61307e565b61041060045481565b610410600a5481565b610410600b5481565b610410610950366004614a08565b6131dc565b610446610963366004614c5c565b6132f3565b610446610976366004614ca8565b6134c5565b610446613685565b6060600061098f611638565b60105490915067ffffffffffffffff8111156109ad576109ad614c79565b6040519080825280602002602001820160405280156109d6578160200160208202803683370190505b5073ffffffffffffffffffffffffffffffffffffffff84166000908152601e602052604090205490925015610afc5760005b601054811015610afa5773ffffffffffffffffffffffffffffffffffffffff84166000818152601760209081526040808320858452825280832054938352601682528083208584529091529020548351670de0b6b3a76400009190859085908110610a7557610a75614d4d565b6020026020010151610a879190614dab565b73ffffffffffffffffffffffffffffffffffffffff87166000908152601e6020526040902054610ab79190614dc2565b610ac19190614dff565b610acb9190614e3a565b838281518110610add57610add614d4d565b602090810291909101015280610af281614e52565b915050610a08565b505b50919050565b600654600754600091610b2891610b198286614dc2565b610b239190614dff565b6136b5565b92915050565b60606010805480602002602001604051908101604052809291908181526020018280548015610b9357602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff168152600190910190602001808311610b68575b5050505050905090565b60005473ffffffffffffffffffffffffffffffffffffffff163314610c49576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602f60248201527f4f6e6c792074686520636f6e7472616374206f776e6572206d6179207065726660448201527f6f726d207468697320616374696f6e000000000000000000000000000000000060648201526084015b60405180910390fd5b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040519081527f906a1c6bd7e3091ea86693dd029a831c19049ce77f1dce2ce0bab1cacbabce229060200160405180910390a150565b60006002805403610d2f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610c40565b60028055610d4033808585426136cd565b60016002559392505050565b60135460609067ffffffffffffffff811115610d6a57610d6a614c79565b604051908082528060200260200182016040528015610d93578160200160208202803683370190505b50905060005b601354811015610de95762093a80610db0826131dc565b610dba9190614dc2565b828281518110610dcc57610dcc614d4d565b602090810291909101015280610de181614e52565b915050610d99565b5090565b73ffffffffffffffffffffffffffffffffffffffff81166000908152602260209081526040808320805482518185028101850190935280835260609492939192909184015b82821015610e9657838290600052602060002090600502016040518060a00160405290816000820154815260200160018201548152602001600282015481526020016003820154815260200160048201548152505081526020019060010190610e32565b505050509050919050565b73ffffffffffffffffffffffffffffffffffffffff81166000908152601f6020526040812054600354670de0b6b3a764000091610edd91614dc2565b610b289190614dff565b6000805473ffffffffffffffffffffffffffffffffffffffff90811690841603610f1357506001610b28565b73ffffffffffffffffffffffffffffffffffffffff8281166000908152600f6020526040902054818516911603610f4c57506001610b28565b50600092915050565b60008080610f6284612496565b905073ffffffffffffffffffffffffffffffffffffffff811615611035576040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff82811660048301527f000000000000000000000000000000000000000000000000000000000000000016906370a0823190602401602060405180830381865afa15801561100c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110309190614e8a565b6110e5565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85811660048301527f000000000000000000000000000000000000000000000000000000000000000016906370a0823190602401602060405180830381865afa1580156110c1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110e59190614e8a565b91506000670de0b6b3a76400007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561115d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111819190614e8a565b61118b9190614dc2565b600954600a5461119b9086614dc2565b6111a59190614dc2565b6111af9190614dff565b905060008073ffffffffffffffffffffffffffffffffffffffff8416156111de576111d984611bb8565b6111e7565b6111e787611353565b9050801561123957600081611204670de0b6b3a764000088614dc2565b61120e9190614dff565b9050670de0b6b3a7640000600a54826112279190614dc2565b6112319190614dff565b92505061123e565b600091505b5080821161124c578061124e565b815b9450600a5485111561126057600a5494505b50505050919050565b60028054036112d4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610c40565b6002805560215462010000900460ff161561134b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f5265776172647320636f6c6c656374696f6e20706175736564000000000000006044820152606401610c40565b506001600255565b6000670de0b6b3a7640000600b5461136a84612992565b610edd9190614dc2565b801561138257611382613685565b73ffffffffffffffffffffffffffffffffffffffff8216156114945760008060006113ac85611db8565b9250925092506113bb85613ad3565b73ffffffffffffffffffffffffffffffffffffffff85166000908152600c6020526040902082905582811061143f5760006113f68483614dab565b905080601c546114069190614e3a565b601c556114138185614e3a565b73ffffffffffffffffffffffffffffffffffffffff87166000908152601e602052604090205550611490565b600061144b8285614dab565b905080601c5461145b9190614dab565b601c556114688185614dab565b73ffffffffffffffffffffffffffffffffffffffff87166000908152601e6020526040902055505b5050505b5050565b60008060008060007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663bcaa64ea426040518263ffffffff1660e01b81526004016114fb91815260200190565b60a060405180830381865afa158015611518573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061153c9190614ec1565b5050506dffffffffffffffffffffffffffff1691506dffffffffffffffffffffffffffff169150602160049054906101000a900460ff161561158057819250611584565b8092505b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156115ef573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116139190614e8a565b61162584670de0b6b3a7640000614dc2565b61162f9190614dff565b95945050505050565b6060601b546000148061164b5750601c54155b156116a5576015805480602002602001604051908101604052809291908181526020018280548015610b9357602002820191906000526020600020905b815481526020019060010190808311611688575050505050905090565b60105467ffffffffffffffff8111156116c0576116c0614c79565b6040519080825280602002602001820160405280156116e9578160200160208202803683370190505b50905060005b601554811015610de957601c54611705826131dc565b600554611710613bd3565b61171a9190614dab565b6117249190614dc2565b61173690670de0b6b3a7640000614dc2565b6117409190614dff565b6015828154811061175357611753614d4d565b90600052602060002001546117689190614e3a565b82828151811061177a5761177a614d4d565b60209081029190910101528061178f81614e52565b9150506116ef565b73ffffffffffffffffffffffffffffffffffffffff821660009081526022602052604081208054829190849081106117d1576117d1614d4d565b600091825260208083206040805160a081018252600590940290910180548452600181015484840181905260028201548584015260038201546060860152600490910154608085015273ffffffffffffffffffffffffffffffffffffffff891685526018909252832054919350111561184f57506020810151611877565b5073ffffffffffffffffffffffffffffffffffffffff84166000908152601860205260409020545b4282606001511161193757606082015173ffffffffffffffffffffffffffffffffffffffff8616600090815260186020526040902054101561192e5760008183606001516118c59190614dab565b905060008360600151426118d99190614dab565b905060006118eb61040b600285614dff565b905060006118f98382614dc2565b6119038584614dc2565b61190d9190614e3a565b90506119198385614e3a565b6119239082614dff565b965050505050611987565b60009250611987565b60008082846060015161194a9190614dab565b9050600042856060015161195e9190614dab565b9050600261196c8284614e3a565b6119769190614dff565b9250505061198381610b02565b9350505b816080015183111561199b57816080015192505b505092915050565b60606002805403611a10576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610c40565b60028055610d40338484613be6565b60226020528160005260406000208181548110611a3b57600080fd5b600091825260209091206005909102018054600182015460028301546003840154600490940154929550909350919085565b60015473ffffffffffffffffffffffffffffffffffffffff163314611b14576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603560248201527f596f75206d757374206265206e6f6d696e61746564206265666f726520796f7560448201527f2063616e20616363657074206f776e65727368697000000000000000000000006064820152608401610c40565b6000546001546040805173ffffffffffffffffffffffffffffffffffffffff93841681529290911660208301527fb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159c910160405180910390a160018054600080547fffffffffffffffffffffffff000000000000000000000000000000000000000090811673ffffffffffffffffffffffffffffffffffffffff841617909155169055565b6000670de0b6b3a7640000600b5461136a84610ea1565b600054829073ffffffffffffffffffffffffffffffffffffffff16331480611bfc5750611bfc3382610ee7565b611c62576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f4e6f74206f776e6572206f7220746b6e206d67720000000000000000000000006044820152606401610c40565b6000805b601054811015611cdc578473ffffffffffffffffffffffffffffffffffffffff1660108281548110611c9a57611c9a614d4d565b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff1603611cca5760019150611cdc565b80611cd481614e52565b915050611c66565b50808015611d10575073ffffffffffffffffffffffffffffffffffffffff8481166000908152600f60205260409020541633145b80611d3b575080158015611d3b575060005473ffffffffffffffffffffffffffffffffffffffff1633145b15611d5157611d4b843385613eb2565b50505050565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f4e6f2076616c696420746f6b656e7320746f207265636f7665720000000000006044820152606401610c40565b505050565b73ffffffffffffffffffffffffffffffffffffffff81166000908152601e60205260408120549080611de984610f55565b73ffffffffffffffffffffffffffffffffffffffff85166000908152601d602052604081205491935090158015611e43575073ffffffffffffffffffffffffffffffffffffffff85166000908152601e6020526040902054155b80611e73575073ffffffffffffffffffffffffffffffffffffffff85166000908152600c60205260409020548310155b15611e7f575081611ebf565b73ffffffffffffffffffffffffffffffffffffffff85166000908152600c6020526040902054600290611eb29085614e3a565b611ebc9190614dff565b90505b6000915060005b73ffffffffffffffffffffffffffffffffffffffff8616600090815260226020526040902054811015611fe35773ffffffffffffffffffffffffffffffffffffffff86166000908152602260205260408120805483908110611f2a57611f2a614d4d565b90600052602060002090600502016040518060a00160405290816000820154815260200160018201548152602001600282015481526020016003820154815260200160048201548152505090506000611f838884611797565b60408301519091506000670de0b6b3a7640000611fa08785614e3a565b611faa9084614dc2565b611fb49190614dff565b611fbe9083614e3a565b9050611fca8188614e3a565b9650505050508080611fdb90614e52565b915050611ec6565b50509193909250565b60005473ffffffffffffffffffffffffffffffffffffffff163314806120255750738412ebf45bac1b340bbe8f318b928c466c4e39ca33145b61208b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b00000000000000000000006044820152606401610c40565b73ffffffffffffffffffffffffffffffffffffffff166000908152600d6020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00811660ff90911615179055565b6000600354600b546120f19190614dc2565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8481166004830152670de0b6b3a76400009182917f000000000000000000000000000000000000000000000000000000000000000016906370a0823190602401602060405180830381865afa158015612189573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121ad9190614e8a565b61136a9190614dc2565b6002805403612222576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610c40565b600280553360016122338282611374565b600080612240338761401b565b9150915060008583604001516122569190614e3a565b90506122847f00000000000000000000000000000000000000000000000000000000000000003330896141e0565b6040805160a0810182528881526020858101518183015281830184905260608087015190830152608080870151908301523360009081526022909152919091208054849081106122d6576122d6614d4d565b9060005260206000209060050201600082015181600001556020820151816001015560408201518160020155606082015181600301556080820151816004015590505085601b600082825461232b9190614e3a565b9091555050336000908152601d60205260408120805488929061234f908490614e3a565b909155506000905061236033612496565b905073ffffffffffffffffffffffffffffffffffffffff8116156123b95773ffffffffffffffffffffffffffffffffffffffff81166000908152601f6020526040812080548992906123b3908490614e3a565b90915550505b506123c5336000611374565b604080518881526020810188905233917f2640b32e7e5d0fa2a21ea06b22fbd75fda0fda384a895a5fdeef43646de47a0c910160405180910390a2505060016002555050505050565b6060600280540361247b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610c40565b6002805561248b33836001613be6565b600160025592915050565b73ffffffffffffffffffffffffffffffffffffffff81166000908152600d602052604081205460ff16156124c8575090565b5073ffffffffffffffffffffffffffffffffffffffff90811660009081526020805260409020541690565b919050565b60005473ffffffffffffffffffffffffffffffffffffffff163314806125315750738412ebf45bac1b340bbe8f318b928c466c4e39ca33145b612597576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b00000000000000000000006044820152606401610c40565b6021805491151562010000027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffff931515610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff951515630100000002959095167fffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff00ff909316929092179390931791909116179055565b6002805403612699576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610c40565b600280553360016126aa8282611374565b6000806126b7338761401b565b91509150428511612724576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4d75737420626520696e207468652066757475726500000000000000000000006044820152606401610c40565b600042836060015111612738576000612748565b4283606001516127489190614dab565b905060006127564288614dab565b90508181116127c1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f43616e6e6f742073686f7274656e206c6f636b2074696d6500000000000000006044820152606401610c40565b60085481101561282d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f4d696e696d756d207374616b652074696d65206e6f74206d65740000000000006044820152606401610c40565b600754811115612899576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f547279696e6720746f206c6f636b20666f7220746f6f206c6f6e6700000000006044820152606401610c40565b6040518060a00160405280898152602001428152602001856040015181526020018881526020016128c983610b02565b90523360009081526022602052604090208054859081106128ec576128ec614d4d565b9060005260206000209060050201600082015181600001556020820151816001015560408201518160020155606082015181600301556080820151816004015590505061293a336000611374565b6040805189815260208101839052428183015260608101899052905133917fc2cf1aae6decacbc52f96b4e4fec96d4ebab5236e4ed987165537bc463014a43919081900360800190a250506001600255505050505050565b73ffffffffffffffffffffffffffffffffffffffff81166000908152601d6020526040812054600354670de0b6b3a764000091610edd91614dc2565b600054849073ffffffffffffffffffffffffffffffffffffffff163314806129fb57506129fb3382610ee7565b612a61576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f4e6f74206f776e6572206f7220746b6e206d67720000000000000000000000006044820152606401610c40565b73ffffffffffffffffffffffffffffffffffffffff8516600090815260146020526040902054601380548692908110612a9c57612a9c614d4d565b9060005260206000200181905550826011601460008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205481548110612afd57612afd614d4d565b600091825260208083209190910180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff948516179055918716815260149091526040902054601280548492908110612b6e57612b6e614d4d565b9060005260206000200160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505050505050565b73ffffffffffffffffffffffffffffffffffffffff81166000908152600d602052604090205460ff16612c4c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f496e76616c69642070726f7879000000000000000000000000000000000000006044820152606401610c40565b73ffffffffffffffffffffffffffffffffffffffff81166000908152600e6020908152604080832033845290915290205460ff16612ce6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f50726f787920686173206e6f7420616c6c6f77656420796f75207965740000006044820152606401610c40565b33600090815260208052604090205473ffffffffffffffffffffffffffffffffffffffff168015612d5b57336000908152601d602090815260408083205473ffffffffffffffffffffffffffffffffffffffff85168452601f9092528220805491929091612d55908490614dab565b90915550505b3360009081526020808052604080832080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff8716908117909155601d835281842054908452601f9092528220805491929091612dcf908490614e3a565b90915550505050565b600054829073ffffffffffffffffffffffffffffffffffffffff16331480612e055750612e053382610ee7565b612e6b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f4e6f74206f776e6572206f7220746b6e206d67720000000000000000000000006044820152606401610c40565b5073ffffffffffffffffffffffffffffffffffffffff9182166000908152600f6020526040902080547fffffffffffffffffffffffff00000000000000000000000000000000000000001691909216179055565b60005473ffffffffffffffffffffffffffffffffffffffff16331480612ef85750738412ebf45bac1b340bbe8f318b928c466c4e39ca33145b612f5e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b00000000000000000000006044820152606401610c40565b602180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00811660ff90911615179055565b60006002805403612ffd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610c40565b60028055602154610100900460ff1615613073576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f5769746864726177616c732070617573656400000000000000000000000000006044820152606401610c40565b610d4033838561437e565b336000908152600d602052604090205460ff166130f7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f496e76616c69642070726f7879000000000000000000000000000000000000006044820152606401610c40565b336000818152600e6020908152604080832073ffffffffffffffffffffffffffffffffffffffff8681168552908352818420805460ff8116157fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff009091161790559180529091205416036131d95773ffffffffffffffffffffffffffffffffffffffff811660009081526020808052604080832080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055601d825280832054338452601f90925282208054919290916131d3908490614dab565b90915550505b50565b600080601183815481106131f2576131f2614d4d565b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff16905080156132cd57670de0b6b3a76400006019848154811061323857613238614d4d565b90600052602060002001548273ffffffffffffffffffffffffffffffffffffffff16630a3be7576040518163ffffffff1660e01b8152600401602060405180830381865afa15801561328e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132b29190614e8a565b6132bc9190614dc2565b6132c69190614dff565b9150610afc565b601383815481106132e0576132e0614d4d565b9060005260206000200154915050919050565b60005b6011548110156114945760006011828154811061331557613315614d4d565b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff16905080156134b25782806133675750601a828154811061335957613359614d4d565b906000526020600020015442115b156134b2576040517f6472eee100000000000000000000000000000000000000000000000000000000815230600482015242602482015273ffffffffffffffffffffffffffffffffffffffff821690636472eee1906044016020604051808303816000875af11580156133de573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134029190614e8a565b6019838154811061341557613415614d4d565b90600052602060002001819055508073ffffffffffffffffffffffffffffffffffffffff1663513872bd6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561346e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134929190614e8a565b601a83815481106134a5576134a5614d4d565b6000918252602090912001555b50806134bd81614e52565b9150506132f6565b60005473ffffffffffffffffffffffffffffffffffffffff163314806134fe5750738412ebf45bac1b340bbe8f318b928c466c4e39ca33145b613564576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b00000000000000000000006044820152606401610c40565b8051670de0b6b3a764000011156135d7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f4d757374206265203e3d204d554c2050524543000000000000000000000000006044820152606401610c40565b60808101516001118015906135f1575060a0810151600111155b613657576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f4d757374206265203e3d203100000000000000000000000000000000000000006044820152606401610c40565b80516006556020810151600a556040810151600b556060810151600955608081015160075560a00151600855565b61368f60006132f3565b613697611498565b60035560045442106136ad576136ab6145df565b565b6136ab614912565b60008183106136c457816136c6565b825b9392505050565b60008560016136dc8282611374565b6021546301000000900460ff1615613750576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f5374616b696e67207061757365640000000000000000000000000000000000006044820152606401610c40565b6008548510156137bc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f4d696e696d756d207374616b652074696d65206e6f74206d65740000000000006044820152606401610c40565b600754851115613828576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f547279696e6720746f206c6f636b20666f7220746f6f206c6f6e6700000000006044820152606401610c40565b6138547f00000000000000000000000000000000000000000000000000000000000000008830896141e0565b600061385f86610b02565b73ffffffffffffffffffffffffffffffffffffffff8a166000908152601d602090815260408083205490517fffffffffffffffffffffffffffffffffffffffff00000000000000000000000060608f901b169281019290925260348201899052605482018b9052607482015291925090609401604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152828252805160209182012073ffffffffffffffffffffffffffffffffffffffff8e1660009081526022835283902060a0850184528185529184018a90529183018b905290925090606081016139528a8a614e3a565b815260209081018590528254600181810185556000948552828520845160059093020191825591830151918101919091556040820151600282015560608201516003820155608090910151600490910155601b80548a92906139b5908490614e3a565b909155505073ffffffffffffffffffffffffffffffffffffffff8a166000908152601d6020526040812080548a92906139ef908490614e3a565b9091555060009050613a008b612496565b905073ffffffffffffffffffffffffffffffffffffffff811615613a595773ffffffffffffffffffffffffffffffffffffffff81166000908152601f6020526040812080548b9290613a53908490614e3a565b90915550505b50613a658a6000611374565b604080518981526020810189905290810182905273ffffffffffffffffffffffffffffffffffffffff8a811660608301528b16907ff400e72e69ef4402819dfc57eeddc66f5eb69bf405e0e8098b1946ec1ac14a229060800160405180910390a29998505050505050505050565b73ffffffffffffffffffffffffffffffffffffffff8116156131d9576000613afa82610983565b905060005b8151811015613b6857818181518110613b1a57613b1a614d4d565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff85166000908152601783526040808220858352909352919091205580613b6081614e52565b915050613aff565b5060005b8151811015611db35760158181548110613b8857613b88614d4d565b600091825260208083209091015473ffffffffffffffffffffffffffffffffffffffff8616835260168252604080842085855290925291205580613bcb81614e52565b915050613b6c565b6000613be1426004546136b5565b905090565b6060836001613bf58282611374565b73ffffffffffffffffffffffffffffffffffffffff8616600090815260186020526040902042905560215462010000900460ff1615613c90576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f5265776172647320636f6c6c656374696f6e20706175736564000000000000006044820152606401610c40565b60105467ffffffffffffffff811115613cab57613cab614c79565b604051908082528060200260200182016040528015613cd4578160200160208202803683370190505b50925060005b601054811015613ea85773ffffffffffffffffffffffffffffffffffffffff871660009081526017602090815260408083208484529091529020548451859083908110613d2957613d29614d4d565b60209081029190910181019190915273ffffffffffffffffffffffffffffffffffffffff881660009081526017825260408082208483529092529081208190558451859083908110613d7d57613d7d614d4d565b60200260200101511115613e9657613dec60108281548110613da157613da1614d4d565b9060005260206000200160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1687868481518110613ddf57613ddf614d4d565b6020026020010151613eb2565b8673ffffffffffffffffffffffffffffffffffffffff167f1d2f2ca53af5d2f333bd32fdd45f9c52ad8ebe31414f7792912077fcb3876dff858381518110613e3657613e36614d4d565b602002602001015160108481548110613e5157613e51614d4d565b600091825260209182902001546040805193845273ffffffffffffffffffffffffffffffffffffffff918216928401929092528a169082015260600160405180910390a25b80613ea081614e52565b915050613cda565b5050509392505050565b6040805173ffffffffffffffffffffffffffffffffffffffff8481166024830152604480830185905283518084039091018152606490920183526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb000000000000000000000000000000000000000000000000000000001790529151600092839290871691613f499190614f4b565b6000604051808303816000865af19150503d8060008114613f86576040519150601f19603f3d011682016040523d82523d6000602084013e613f8b565b606091505b5091509150818015613fb5575080511580613fb5575080806020019051810190613fb59190614f67565b611490576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5472616e7366657248656c7065723a205452414e534645525f4641494c4544006044820152606401610c40565b6140506040518060a0016040528060008019168152602001600081526020016000815260200160008152602001600081525090565b6000805b73ffffffffffffffffffffffffffffffffffffffff851660009081526022602052604090205481101561416e5773ffffffffffffffffffffffffffffffffffffffff851660009081526022602052604090208054829081106140b8576140b8614d4d565b906000526020600020906005020160000154840361415c5773ffffffffffffffffffffffffffffffffffffffff8516600090815260226020526040902080548290811061410757614107614d4d565b90600052602060002090600502016040518060a001604052908160008201548152602001600182015481526020016002820154815260200160038201548152602001600482015481525050925080915061416e565b8061416681614e52565b915050614054565b50815183146141d9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f5374616b65206e6f7420666f756e6400000000000000000000000000000000006044820152606401610c40565b9250929050565b6040805173ffffffffffffffffffffffffffffffffffffffff85811660248301528481166044830152606480830185905283518084039091018152608490920183526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f23b872dd00000000000000000000000000000000000000000000000000000000179052915160009283929088169161427f9190614f4b565b6000604051808303816000865af19150503d80600081146142bc576040519150601f19603f3d011682016040523d82523d6000602084013e6142c1565b606091505b50915091508180156142eb5750805115806142eb5750808060200190518101906142eb9190614f67565b614376576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f5472616e7366657248656c7065723a205452414e534645525f46524f4d5f464160448201527f494c4544000000000000000000000000000000000000000000000000000000006064820152608401610c40565b505050505050565b600061438c84846001613be6565b5060008061439a868561401b565b915091508160600151421015806143b8575060215460ff1615156001145b61441e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f5374616b65206973207374696c6c206c6f636b656421000000000000000000006044820152606401610c40565b604082015180156145d5576144547f00000000000000000000000000000000000000000000000000000000000000008783613eb2565b80601b60008282546144669190614dab565b909155505073ffffffffffffffffffffffffffffffffffffffff87166000908152601d6020526040812080548392906144a0908490614dab565b90915550600090506144b188612496565b905073ffffffffffffffffffffffffffffffffffffffff81161561450a5773ffffffffffffffffffffffffffffffffffffffff81166000908152601f602052604081208054849290614504908490614dab565b90915550505b5073ffffffffffffffffffffffffffffffffffffffff8716600090815260226020526040902080548390811061454257614542614d4d565b60009182526020822060059091020181815560018101829055600281018290556003810182905560040181905561457a908890611374565b604080518281526020810187905273ffffffffffffffffffffffffffffffffffffffff888116828401529151918916917f1d9308f6b22a2754a1c622bb30889e8f8f956c83e524d039e9d65d5f052eb9089181900360600190a25b9695505050505050565b60005b6012548110156146d05760006012828154811061460157614601614d4d565b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff16905080156146bd576040517f092193ab00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff82169063092193ab9060240160408051808303816000875af1158015614696573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906146ba9190614f84565b50505b50806146c881614e52565b9150506145e2565b50600062093a80600454426146e59190614dab565b6146ef9190614dff565b905060005b6010548110156148d2576010818154811061471157614711614d4d565b6000918252602090912001546040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff909116906370a0823190602401602060405180830381865afa158015614788573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906147ac9190614e8a565b6147b7836001614e3a565b62093a806147c4846131dc565b6147ce9190614dc2565b6147d89190614dc2565b1115601082815481106147ed576147ed614d4d565b60009182526020918290200154604080517f4e6f7420656e6f7567682072657761726420746f6b656e7320617661696c6162938101939093527f6c653a20000000000000000000000000000000000000000000000000000000009083015260601b7fffffffffffffffffffffffffffffffffffffffff000000000000000000000000166044820152605801604051602081830303815290604052906148bf576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c409190614fa8565b50806148ca81614e52565b9150506146f4565b5062093a806148e2826001614e3a565b6148ec9190614dc2565b6004546148f99190614e3a565b600455614904614912565b61490c611498565b60035550565b600061491c611638565b905060005b6015548110156149765781818151811061493d5761493d614d4d565b60200260200101516015828154811061495857614958614d4d565b6000918252602090912001558061496e81614e52565b915050614921565b5061497f613bd3565b60055550565b803573ffffffffffffffffffffffffffffffffffffffff811681146124f357600080fd5b6000602082840312156149bb57600080fd5b6136c682614985565b6020808252825182820181905260009190848201906040850190845b818110156149fc578351835292840192918401916001016149e0565b50909695505050505050565b600060208284031215614a1a57600080fd5b5035919050565b6020808252825182820181905260009190848201906040850190845b818110156149fc57835173ffffffffffffffffffffffffffffffffffffffff1683529284019291840191600101614a3d565b60008060408385031215614a8257600080fd5b50508035926020909101359150565b602080825282518282018190526000919060409081850190868401855b82811015614af25781518051855286810151878601528581015186860152606080820151908601526080908101519085015260a09093019290850190600101614aae565b5091979650505050505050565b60008060408385031215614b1257600080fd5b614b1b83614985565b9150614b2960208401614985565b90509250929050565b80151581146131d957600080fd5b60008060408385031215614b5357600080fd5b614b5c83614985565b91506020830135614b6c81614b32565b809150509250929050565b60008060408385031215614b8a57600080fd5b614b9383614985565b946020939093013593505050565b600080600060608486031215614bb657600080fd5b8335614bc181614b32565b92506020840135614bd181614b32565b91506040840135614be181614b32565b809150509250925092565b60008060008060808587031215614c0257600080fd5b614c0b85614985565b935060208501359250614c2060408601614985565b9150614c2e60608601614985565b905092959194509250565b60008060408385031215614c4c57600080fd5b82359150614b2960208401614985565b600060208284031215614c6e57600080fd5b81356136c681614b32565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600060c08284031215614cba57600080fd5b82601f830112614cc957600080fd5b60405160c0810181811067ffffffffffffffff82111715614d13577f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040528060c0840185811115614d2857600080fd5b845b81811015614d42578035835260209283019201614d2a565b509195945050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600082821015614dbd57614dbd614d7c565b500390565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615614dfa57614dfa614d7c565b500290565b600082614e35577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b60008219821115614e4d57614e4d614d7c565b500190565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203614e8357614e83614d7c565b5060010190565b600060208284031215614e9c57600080fd5b5051919050565b80516dffffffffffffffffffffffffffff811681146124f357600080fd5b600080600080600060a08688031215614ed957600080fd5b614ee286614ea3565b9450614ef060208701614ea3565b935060408601519250614f0560608701614ea3565b9150614f1360808701614ea3565b90509295509295909350565b60005b83811015614f3a578181015183820152602001614f22565b83811115611d4b5750506000910152565b60008251614f5d818460208701614f1f565b9190910192915050565b600060208284031215614f7957600080fd5b81516136c681614b32565b60008060408385031215614f9757600080fd5b505080516020909101519092909150565b6020815260008251806020840152614fc7816040850160208701614f1f565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016919091016040019291505056fea2646970667358221220d1bcf14daa5da273eb104d6a8414d0641f8933549ff1680562afa0fd13d7084664736f6c634300080f0033000000000000000000000000ff5b4bcbf765fe363269114e1c765229a29edefd00000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000000000000001a000000000000000000000000000000000000000000000000000000000000001e000000000000000000000000003b59bd1c8b9f6c265ba0c3421923b93f15036fa00000000000000000000000000000000000000000000000000000000000000010000000000000000000000003432b6a60d23ca0dfca7761b7ab56459d9c964d00000000000000000000000000000000000000000000000000000000000000001000000000000000000000000b1748c79709f4ba2dd82834b8c82d4a505003f27000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000a86cc92e3da000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000278dc748eda1d8efef1adfb518542612b49fcd34
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106103cf5760003560e01c80638bad86a7116101ff578063d42fc9b41161011a578063e7f30582116100ad578063f2caeb1e1161007c578063f2caeb1e14610942578063f77e34d114610955578063facefb6414610968578063fff6cae91461097b57600080fd5b8063e7f3058214610914578063ebe2b12b14610927578063f288baf614610930578063f2a8d3491461093957600080fd5b8063de1a6551116100e9578063de1a6551146108de578063e01f62bf146108f1578063e1ba95d2146108f9578063e44b9fa51461090157600080fd5b8063d42fc9b41461086f578063d5e1a9c614610882578063d7400d5614610895578063d9f96e8d146108a857600080fd5b8063c00007b011610192578063cc2abd6411610161578063cc2abd6414610837578063cdc82e801461084a578063d2010fb414610853578063d2fbdc0d1461085c57600080fd5b8063c00007b0146107d2578063c3543826146107e5578063c8f33c91146107f8578063ca6df29d1461080157600080fd5b8063a0f23476116101ce578063a0f234761461079a578063aa1d4fce146107ad578063b85efd06146107b6578063b94c4dcb146107c957600080fd5b80638bad86a71461072c5780638da5cb5b1461075a57806391cf600a1461077a5780639637927f1461078d57600080fd5b806353a47bb7116102ef57806372f702f31161028257806379ba50971161025157806379ba5097146106de5780637d6ef08e146106e65780637f472e54146107065780638980f11f1461071957600080fd5b806372f702f314610656578063774d4ae71461067d5780637910d17b146106905780637970833e146106a357600080fd5b806369339245116102be57806369339245146106055780636c430dbb146106255780636e27cef91461064557806370641a361461064e57600080fd5b806353a47bb7146105c257806355189773146105e25780635bfd9258146105f557806364f2c060146105fd57600080fd5b8063231b68dc11610367578063386a952511610336578063386a95251461055c578063387edc861461056657806341a16f3f146105795780634fd2b536146105af57600080fd5b8063231b68dc1461049657806328408bab146104b95780632c0c2a0a1461051357806336f89af21461052657600080fd5b806317b18c89116103a357806317b18c89146104485780631c1f78eb1461045b5780631e090f01146104635780631face8561461048357600080fd5b80628cc262146103d45780630d7bac4f146103fd57806312edb24c1461041e5780631627540c14610433575b600080fd5b6103e76103e23660046149a9565b610983565b6040516103f491906149c4565b60405180910390f35b61041061040b366004614a08565b610b02565b6040519081526020016103f4565b610426610b2e565b6040516103f49190614a21565b6104466104413660046149a9565b610b9d565b005b610410610456366004614a6f565b610cc2565b6103e7610d4c565b6104766104713660046149a9565b610ded565b6040516103f49190614a91565b6104106104913660046149a9565b610ea1565b6104a96104a4366004614aff565b610ee7565b60405190151581526020016103f4565b6104ee6104c73660046149a9565b602080526000908152604090205473ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016103f4565b6104106105213660046149a9565b610f55565b6104106105343660046149a9565b73ffffffffffffffffffffffffffffffffffffffff166000908152601e602052604090205490565b61041062093a8081565b6104466105743660046149a9565b611269565b6104ee6105873660046149a9565b600f6020526000908152604090205473ffffffffffffffffffffffffffffffffffffffff1681565b6104106105bd3660046149a9565b611353565b6001546104ee9073ffffffffffffffffffffffffffffffffffffffff1681565b6104466105f0366004614b40565b611374565b610410611498565b601c54610410565b6104106106133660046149a9565b60146020526000908152604090205481565b6104106106333660046149a9565b60186020526000908152604090205481565b61041060085481565b6103e7611638565b6104ee7f00000000000000000000000003b59bd1c8b9f6c265ba0c3421923b93f15036fa81565b61041061068b366004614b77565b611797565b6103e761069e366004614b40565b6119a3565b6106b66106b1366004614b77565b611a1f565b604080519586526020860194909452928401919091526060830152608082015260a0016103f4565b610446611a6d565b6104106106f43660046149a9565b601f6020526000908152604090205481565b6104106107143660046149a9565b611bb8565b610446610727366004614b77565b611bcf565b61073f61073a3660046149a9565b611db8565b604080519384526020840192909252908201526060016103f4565b6000546104ee9073ffffffffffffffffffffffffffffffffffffffff1681565b6104466107883660046149a9565b611fec565b6021546104a99060ff1681565b6104106107a83660046149a9565b6120df565b61041060095481565b6104466107c4366004614a6f565b6121b7565b61041060075481565b6103e76107e03660046149a9565b61240e565b6104ee6107f33660046149a9565b612496565b61041060055481565b61041061080f3660046149a9565b73ffffffffffffffffffffffffffffffffffffffff1660009081526022602052604090205490565b610446610845366004614ba1565b6124f8565b61041060065481565b61041060035481565b61044661086a366004614a6f565b61262e565b61041061087d3660046149a9565b612992565b610446610890366004614bec565b6129ce565b6104466108a33660046149a9565b612bbd565b6104106108b63660046149a9565b73ffffffffffffffffffffffffffffffffffffffff166000908152601d602052604090205490565b6104466108ec366004614aff565b612dd8565b601b54610410565b610446612ebf565b61041061090f366004614c39565b612f90565b6104466109223660046149a9565b61307e565b61041060045481565b610410600a5481565b610410600b5481565b610410610950366004614a08565b6131dc565b610446610963366004614c5c565b6132f3565b610446610976366004614ca8565b6134c5565b610446613685565b6060600061098f611638565b60105490915067ffffffffffffffff8111156109ad576109ad614c79565b6040519080825280602002602001820160405280156109d6578160200160208202803683370190505b5073ffffffffffffffffffffffffffffffffffffffff84166000908152601e602052604090205490925015610afc5760005b601054811015610afa5773ffffffffffffffffffffffffffffffffffffffff84166000818152601760209081526040808320858452825280832054938352601682528083208584529091529020548351670de0b6b3a76400009190859085908110610a7557610a75614d4d565b6020026020010151610a879190614dab565b73ffffffffffffffffffffffffffffffffffffffff87166000908152601e6020526040902054610ab79190614dc2565b610ac19190614dff565b610acb9190614e3a565b838281518110610add57610add614d4d565b602090810291909101015280610af281614e52565b915050610a08565b505b50919050565b600654600754600091610b2891610b198286614dc2565b610b239190614dff565b6136b5565b92915050565b60606010805480602002602001604051908101604052809291908181526020018280548015610b9357602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff168152600190910190602001808311610b68575b5050505050905090565b60005473ffffffffffffffffffffffffffffffffffffffff163314610c49576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602f60248201527f4f6e6c792074686520636f6e7472616374206f776e6572206d6179207065726660448201527f6f726d207468697320616374696f6e000000000000000000000000000000000060648201526084015b60405180910390fd5b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040519081527f906a1c6bd7e3091ea86693dd029a831c19049ce77f1dce2ce0bab1cacbabce229060200160405180910390a150565b60006002805403610d2f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610c40565b60028055610d4033808585426136cd565b60016002559392505050565b60135460609067ffffffffffffffff811115610d6a57610d6a614c79565b604051908082528060200260200182016040528015610d93578160200160208202803683370190505b50905060005b601354811015610de95762093a80610db0826131dc565b610dba9190614dc2565b828281518110610dcc57610dcc614d4d565b602090810291909101015280610de181614e52565b915050610d99565b5090565b73ffffffffffffffffffffffffffffffffffffffff81166000908152602260209081526040808320805482518185028101850190935280835260609492939192909184015b82821015610e9657838290600052602060002090600502016040518060a00160405290816000820154815260200160018201548152602001600282015481526020016003820154815260200160048201548152505081526020019060010190610e32565b505050509050919050565b73ffffffffffffffffffffffffffffffffffffffff81166000908152601f6020526040812054600354670de0b6b3a764000091610edd91614dc2565b610b289190614dff565b6000805473ffffffffffffffffffffffffffffffffffffffff90811690841603610f1357506001610b28565b73ffffffffffffffffffffffffffffffffffffffff8281166000908152600f6020526040902054818516911603610f4c57506001610b28565b50600092915050565b60008080610f6284612496565b905073ffffffffffffffffffffffffffffffffffffffff811615611035576040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff82811660048301527f000000000000000000000000c8418af6358ffdda74e09ca9cc3fe03ca6adc5b016906370a0823190602401602060405180830381865afa15801561100c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110309190614e8a565b6110e5565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85811660048301527f000000000000000000000000c8418af6358ffdda74e09ca9cc3fe03ca6adc5b016906370a0823190602401602060405180830381865afa1580156110c1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110e59190614e8a565b91506000670de0b6b3a76400007f000000000000000000000000c8418af6358ffdda74e09ca9cc3fe03ca6adc5b073ffffffffffffffffffffffffffffffffffffffff166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561115d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111819190614e8a565b61118b9190614dc2565b600954600a5461119b9086614dc2565b6111a59190614dc2565b6111af9190614dff565b905060008073ffffffffffffffffffffffffffffffffffffffff8416156111de576111d984611bb8565b6111e7565b6111e787611353565b9050801561123957600081611204670de0b6b3a764000088614dc2565b61120e9190614dff565b9050670de0b6b3a7640000600a54826112279190614dc2565b6112319190614dff565b92505061123e565b600091505b5080821161124c578061124e565b815b9450600a5485111561126057600a5494505b50505050919050565b60028054036112d4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610c40565b6002805560215462010000900460ff161561134b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f5265776172647320636f6c6c656374696f6e20706175736564000000000000006044820152606401610c40565b506001600255565b6000670de0b6b3a7640000600b5461136a84612992565b610edd9190614dc2565b801561138257611382613685565b73ffffffffffffffffffffffffffffffffffffffff8216156114945760008060006113ac85611db8565b9250925092506113bb85613ad3565b73ffffffffffffffffffffffffffffffffffffffff85166000908152600c6020526040902082905582811061143f5760006113f68483614dab565b905080601c546114069190614e3a565b601c556114138185614e3a565b73ffffffffffffffffffffffffffffffffffffffff87166000908152601e602052604090205550611490565b600061144b8285614dab565b905080601c5461145b9190614dab565b601c556114688185614dab565b73ffffffffffffffffffffffffffffffffffffffff87166000908152601e6020526040902055505b5050505b5050565b60008060008060007f00000000000000000000000003b59bd1c8b9f6c265ba0c3421923b93f15036fa73ffffffffffffffffffffffffffffffffffffffff1663bcaa64ea426040518263ffffffff1660e01b81526004016114fb91815260200190565b60a060405180830381865afa158015611518573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061153c9190614ec1565b5050506dffffffffffffffffffffffffffff1691506dffffffffffffffffffffffffffff169150602160049054906101000a900460ff161561158057819250611584565b8092505b7f00000000000000000000000003b59bd1c8b9f6c265ba0c3421923b93f15036fa73ffffffffffffffffffffffffffffffffffffffff166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156115ef573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116139190614e8a565b61162584670de0b6b3a7640000614dc2565b61162f9190614dff565b95945050505050565b6060601b546000148061164b5750601c54155b156116a5576015805480602002602001604051908101604052809291908181526020018280548015610b9357602002820191906000526020600020905b815481526020019060010190808311611688575050505050905090565b60105467ffffffffffffffff8111156116c0576116c0614c79565b6040519080825280602002602001820160405280156116e9578160200160208202803683370190505b50905060005b601554811015610de957601c54611705826131dc565b600554611710613bd3565b61171a9190614dab565b6117249190614dc2565b61173690670de0b6b3a7640000614dc2565b6117409190614dff565b6015828154811061175357611753614d4d565b90600052602060002001546117689190614e3a565b82828151811061177a5761177a614d4d565b60209081029190910101528061178f81614e52565b9150506116ef565b73ffffffffffffffffffffffffffffffffffffffff821660009081526022602052604081208054829190849081106117d1576117d1614d4d565b600091825260208083206040805160a081018252600590940290910180548452600181015484840181905260028201548584015260038201546060860152600490910154608085015273ffffffffffffffffffffffffffffffffffffffff891685526018909252832054919350111561184f57506020810151611877565b5073ffffffffffffffffffffffffffffffffffffffff84166000908152601860205260409020545b4282606001511161193757606082015173ffffffffffffffffffffffffffffffffffffffff8616600090815260186020526040902054101561192e5760008183606001516118c59190614dab565b905060008360600151426118d99190614dab565b905060006118eb61040b600285614dff565b905060006118f98382614dc2565b6119038584614dc2565b61190d9190614e3a565b90506119198385614e3a565b6119239082614dff565b965050505050611987565b60009250611987565b60008082846060015161194a9190614dab565b9050600042856060015161195e9190614dab565b9050600261196c8284614e3a565b6119769190614dff565b9250505061198381610b02565b9350505b816080015183111561199b57816080015192505b505092915050565b60606002805403611a10576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610c40565b60028055610d40338484613be6565b60226020528160005260406000208181548110611a3b57600080fd5b600091825260209091206005909102018054600182015460028301546003840154600490940154929550909350919085565b60015473ffffffffffffffffffffffffffffffffffffffff163314611b14576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603560248201527f596f75206d757374206265206e6f6d696e61746564206265666f726520796f7560448201527f2063616e20616363657074206f776e65727368697000000000000000000000006064820152608401610c40565b6000546001546040805173ffffffffffffffffffffffffffffffffffffffff93841681529290911660208301527fb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159c910160405180910390a160018054600080547fffffffffffffffffffffffff000000000000000000000000000000000000000090811673ffffffffffffffffffffffffffffffffffffffff841617909155169055565b6000670de0b6b3a7640000600b5461136a84610ea1565b600054829073ffffffffffffffffffffffffffffffffffffffff16331480611bfc5750611bfc3382610ee7565b611c62576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f4e6f74206f776e6572206f7220746b6e206d67720000000000000000000000006044820152606401610c40565b6000805b601054811015611cdc578473ffffffffffffffffffffffffffffffffffffffff1660108281548110611c9a57611c9a614d4d565b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff1603611cca5760019150611cdc565b80611cd481614e52565b915050611c66565b50808015611d10575073ffffffffffffffffffffffffffffffffffffffff8481166000908152600f60205260409020541633145b80611d3b575080158015611d3b575060005473ffffffffffffffffffffffffffffffffffffffff1633145b15611d5157611d4b843385613eb2565b50505050565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f4e6f2076616c696420746f6b656e7320746f207265636f7665720000000000006044820152606401610c40565b505050565b73ffffffffffffffffffffffffffffffffffffffff81166000908152601e60205260408120549080611de984610f55565b73ffffffffffffffffffffffffffffffffffffffff85166000908152601d602052604081205491935090158015611e43575073ffffffffffffffffffffffffffffffffffffffff85166000908152601e6020526040902054155b80611e73575073ffffffffffffffffffffffffffffffffffffffff85166000908152600c60205260409020548310155b15611e7f575081611ebf565b73ffffffffffffffffffffffffffffffffffffffff85166000908152600c6020526040902054600290611eb29085614e3a565b611ebc9190614dff565b90505b6000915060005b73ffffffffffffffffffffffffffffffffffffffff8616600090815260226020526040902054811015611fe35773ffffffffffffffffffffffffffffffffffffffff86166000908152602260205260408120805483908110611f2a57611f2a614d4d565b90600052602060002090600502016040518060a00160405290816000820154815260200160018201548152602001600282015481526020016003820154815260200160048201548152505090506000611f838884611797565b60408301519091506000670de0b6b3a7640000611fa08785614e3a565b611faa9084614dc2565b611fb49190614dff565b611fbe9083614e3a565b9050611fca8188614e3a565b9650505050508080611fdb90614e52565b915050611ec6565b50509193909250565b60005473ffffffffffffffffffffffffffffffffffffffff163314806120255750738412ebf45bac1b340bbe8f318b928c466c4e39ca33145b61208b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b00000000000000000000006044820152606401610c40565b73ffffffffffffffffffffffffffffffffffffffff166000908152600d6020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00811660ff90911615179055565b6000600354600b546120f19190614dc2565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8481166004830152670de0b6b3a76400009182917f000000000000000000000000c8418af6358ffdda74e09ca9cc3fe03ca6adc5b016906370a0823190602401602060405180830381865afa158015612189573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121ad9190614e8a565b61136a9190614dc2565b6002805403612222576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610c40565b600280553360016122338282611374565b600080612240338761401b565b9150915060008583604001516122569190614e3a565b90506122847f00000000000000000000000003b59bd1c8b9f6c265ba0c3421923b93f15036fa3330896141e0565b6040805160a0810182528881526020858101518183015281830184905260608087015190830152608080870151908301523360009081526022909152919091208054849081106122d6576122d6614d4d565b9060005260206000209060050201600082015181600001556020820151816001015560408201518160020155606082015181600301556080820151816004015590505085601b600082825461232b9190614e3a565b9091555050336000908152601d60205260408120805488929061234f908490614e3a565b909155506000905061236033612496565b905073ffffffffffffffffffffffffffffffffffffffff8116156123b95773ffffffffffffffffffffffffffffffffffffffff81166000908152601f6020526040812080548992906123b3908490614e3a565b90915550505b506123c5336000611374565b604080518881526020810188905233917f2640b32e7e5d0fa2a21ea06b22fbd75fda0fda384a895a5fdeef43646de47a0c910160405180910390a2505060016002555050505050565b6060600280540361247b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610c40565b6002805561248b33836001613be6565b600160025592915050565b73ffffffffffffffffffffffffffffffffffffffff81166000908152600d602052604081205460ff16156124c8575090565b5073ffffffffffffffffffffffffffffffffffffffff90811660009081526020805260409020541690565b919050565b60005473ffffffffffffffffffffffffffffffffffffffff163314806125315750738412ebf45bac1b340bbe8f318b928c466c4e39ca33145b612597576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b00000000000000000000006044820152606401610c40565b6021805491151562010000027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffff931515610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff951515630100000002959095167fffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff00ff909316929092179390931791909116179055565b6002805403612699576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610c40565b600280553360016126aa8282611374565b6000806126b7338761401b565b91509150428511612724576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4d75737420626520696e207468652066757475726500000000000000000000006044820152606401610c40565b600042836060015111612738576000612748565b4283606001516127489190614dab565b905060006127564288614dab565b90508181116127c1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f43616e6e6f742073686f7274656e206c6f636b2074696d6500000000000000006044820152606401610c40565b60085481101561282d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f4d696e696d756d207374616b652074696d65206e6f74206d65740000000000006044820152606401610c40565b600754811115612899576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f547279696e6720746f206c6f636b20666f7220746f6f206c6f6e6700000000006044820152606401610c40565b6040518060a00160405280898152602001428152602001856040015181526020018881526020016128c983610b02565b90523360009081526022602052604090208054859081106128ec576128ec614d4d565b9060005260206000209060050201600082015181600001556020820151816001015560408201518160020155606082015181600301556080820151816004015590505061293a336000611374565b6040805189815260208101839052428183015260608101899052905133917fc2cf1aae6decacbc52f96b4e4fec96d4ebab5236e4ed987165537bc463014a43919081900360800190a250506001600255505050505050565b73ffffffffffffffffffffffffffffffffffffffff81166000908152601d6020526040812054600354670de0b6b3a764000091610edd91614dc2565b600054849073ffffffffffffffffffffffffffffffffffffffff163314806129fb57506129fb3382610ee7565b612a61576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f4e6f74206f776e6572206f7220746b6e206d67720000000000000000000000006044820152606401610c40565b73ffffffffffffffffffffffffffffffffffffffff8516600090815260146020526040902054601380548692908110612a9c57612a9c614d4d565b9060005260206000200181905550826011601460008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205481548110612afd57612afd614d4d565b600091825260208083209190910180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff948516179055918716815260149091526040902054601280548492908110612b6e57612b6e614d4d565b9060005260206000200160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505050505050565b73ffffffffffffffffffffffffffffffffffffffff81166000908152600d602052604090205460ff16612c4c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f496e76616c69642070726f7879000000000000000000000000000000000000006044820152606401610c40565b73ffffffffffffffffffffffffffffffffffffffff81166000908152600e6020908152604080832033845290915290205460ff16612ce6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f50726f787920686173206e6f7420616c6c6f77656420796f75207965740000006044820152606401610c40565b33600090815260208052604090205473ffffffffffffffffffffffffffffffffffffffff168015612d5b57336000908152601d602090815260408083205473ffffffffffffffffffffffffffffffffffffffff85168452601f9092528220805491929091612d55908490614dab565b90915550505b3360009081526020808052604080832080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff8716908117909155601d835281842054908452601f9092528220805491929091612dcf908490614e3a565b90915550505050565b600054829073ffffffffffffffffffffffffffffffffffffffff16331480612e055750612e053382610ee7565b612e6b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f4e6f74206f776e6572206f7220746b6e206d67720000000000000000000000006044820152606401610c40565b5073ffffffffffffffffffffffffffffffffffffffff9182166000908152600f6020526040902080547fffffffffffffffffffffffff00000000000000000000000000000000000000001691909216179055565b60005473ffffffffffffffffffffffffffffffffffffffff16331480612ef85750738412ebf45bac1b340bbe8f318b928c466c4e39ca33145b612f5e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b00000000000000000000006044820152606401610c40565b602180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00811660ff90911615179055565b60006002805403612ffd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610c40565b60028055602154610100900460ff1615613073576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f5769746864726177616c732070617573656400000000000000000000000000006044820152606401610c40565b610d4033838561437e565b336000908152600d602052604090205460ff166130f7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f496e76616c69642070726f7879000000000000000000000000000000000000006044820152606401610c40565b336000818152600e6020908152604080832073ffffffffffffffffffffffffffffffffffffffff8681168552908352818420805460ff8116157fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff009091161790559180529091205416036131d95773ffffffffffffffffffffffffffffffffffffffff811660009081526020808052604080832080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055601d825280832054338452601f90925282208054919290916131d3908490614dab565b90915550505b50565b600080601183815481106131f2576131f2614d4d565b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff16905080156132cd57670de0b6b3a76400006019848154811061323857613238614d4d565b90600052602060002001548273ffffffffffffffffffffffffffffffffffffffff16630a3be7576040518163ffffffff1660e01b8152600401602060405180830381865afa15801561328e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132b29190614e8a565b6132bc9190614dc2565b6132c69190614dff565b9150610afc565b601383815481106132e0576132e0614d4d565b9060005260206000200154915050919050565b60005b6011548110156114945760006011828154811061331557613315614d4d565b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff16905080156134b25782806133675750601a828154811061335957613359614d4d565b906000526020600020015442115b156134b2576040517f6472eee100000000000000000000000000000000000000000000000000000000815230600482015242602482015273ffffffffffffffffffffffffffffffffffffffff821690636472eee1906044016020604051808303816000875af11580156133de573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134029190614e8a565b6019838154811061341557613415614d4d565b90600052602060002001819055508073ffffffffffffffffffffffffffffffffffffffff1663513872bd6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561346e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134929190614e8a565b601a83815481106134a5576134a5614d4d565b6000918252602090912001555b50806134bd81614e52565b9150506132f6565b60005473ffffffffffffffffffffffffffffffffffffffff163314806134fe5750738412ebf45bac1b340bbe8f318b928c466c4e39ca33145b613564576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b00000000000000000000006044820152606401610c40565b8051670de0b6b3a764000011156135d7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f4d757374206265203e3d204d554c2050524543000000000000000000000000006044820152606401610c40565b60808101516001118015906135f1575060a0810151600111155b613657576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f4d757374206265203e3d203100000000000000000000000000000000000000006044820152606401610c40565b80516006556020810151600a556040810151600b556060810151600955608081015160075560a00151600855565b61368f60006132f3565b613697611498565b60035560045442106136ad576136ab6145df565b565b6136ab614912565b60008183106136c457816136c6565b825b9392505050565b60008560016136dc8282611374565b6021546301000000900460ff1615613750576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f5374616b696e67207061757365640000000000000000000000000000000000006044820152606401610c40565b6008548510156137bc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f4d696e696d756d207374616b652074696d65206e6f74206d65740000000000006044820152606401610c40565b600754851115613828576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f547279696e6720746f206c6f636b20666f7220746f6f206c6f6e6700000000006044820152606401610c40565b6138547f00000000000000000000000003b59bd1c8b9f6c265ba0c3421923b93f15036fa8830896141e0565b600061385f86610b02565b73ffffffffffffffffffffffffffffffffffffffff8a166000908152601d602090815260408083205490517fffffffffffffffffffffffffffffffffffffffff00000000000000000000000060608f901b169281019290925260348201899052605482018b9052607482015291925090609401604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152828252805160209182012073ffffffffffffffffffffffffffffffffffffffff8e1660009081526022835283902060a0850184528185529184018a90529183018b905290925090606081016139528a8a614e3a565b815260209081018590528254600181810185556000948552828520845160059093020191825591830151918101919091556040820151600282015560608201516003820155608090910151600490910155601b80548a92906139b5908490614e3a565b909155505073ffffffffffffffffffffffffffffffffffffffff8a166000908152601d6020526040812080548a92906139ef908490614e3a565b9091555060009050613a008b612496565b905073ffffffffffffffffffffffffffffffffffffffff811615613a595773ffffffffffffffffffffffffffffffffffffffff81166000908152601f6020526040812080548b9290613a53908490614e3a565b90915550505b50613a658a6000611374565b604080518981526020810189905290810182905273ffffffffffffffffffffffffffffffffffffffff8a811660608301528b16907ff400e72e69ef4402819dfc57eeddc66f5eb69bf405e0e8098b1946ec1ac14a229060800160405180910390a29998505050505050505050565b73ffffffffffffffffffffffffffffffffffffffff8116156131d9576000613afa82610983565b905060005b8151811015613b6857818181518110613b1a57613b1a614d4d565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff85166000908152601783526040808220858352909352919091205580613b6081614e52565b915050613aff565b5060005b8151811015611db35760158181548110613b8857613b88614d4d565b600091825260208083209091015473ffffffffffffffffffffffffffffffffffffffff8616835260168252604080842085855290925291205580613bcb81614e52565b915050613b6c565b6000613be1426004546136b5565b905090565b6060836001613bf58282611374565b73ffffffffffffffffffffffffffffffffffffffff8616600090815260186020526040902042905560215462010000900460ff1615613c90576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f5265776172647320636f6c6c656374696f6e20706175736564000000000000006044820152606401610c40565b60105467ffffffffffffffff811115613cab57613cab614c79565b604051908082528060200260200182016040528015613cd4578160200160208202803683370190505b50925060005b601054811015613ea85773ffffffffffffffffffffffffffffffffffffffff871660009081526017602090815260408083208484529091529020548451859083908110613d2957613d29614d4d565b60209081029190910181019190915273ffffffffffffffffffffffffffffffffffffffff881660009081526017825260408082208483529092529081208190558451859083908110613d7d57613d7d614d4d565b60200260200101511115613e9657613dec60108281548110613da157613da1614d4d565b9060005260206000200160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1687868481518110613ddf57613ddf614d4d565b6020026020010151613eb2565b8673ffffffffffffffffffffffffffffffffffffffff167f1d2f2ca53af5d2f333bd32fdd45f9c52ad8ebe31414f7792912077fcb3876dff858381518110613e3657613e36614d4d565b602002602001015160108481548110613e5157613e51614d4d565b600091825260209182902001546040805193845273ffffffffffffffffffffffffffffffffffffffff918216928401929092528a169082015260600160405180910390a25b80613ea081614e52565b915050613cda565b5050509392505050565b6040805173ffffffffffffffffffffffffffffffffffffffff8481166024830152604480830185905283518084039091018152606490920183526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb000000000000000000000000000000000000000000000000000000001790529151600092839290871691613f499190614f4b565b6000604051808303816000865af19150503d8060008114613f86576040519150601f19603f3d011682016040523d82523d6000602084013e613f8b565b606091505b5091509150818015613fb5575080511580613fb5575080806020019051810190613fb59190614f67565b611490576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5472616e7366657248656c7065723a205452414e534645525f4641494c4544006044820152606401610c40565b6140506040518060a0016040528060008019168152602001600081526020016000815260200160008152602001600081525090565b6000805b73ffffffffffffffffffffffffffffffffffffffff851660009081526022602052604090205481101561416e5773ffffffffffffffffffffffffffffffffffffffff851660009081526022602052604090208054829081106140b8576140b8614d4d565b906000526020600020906005020160000154840361415c5773ffffffffffffffffffffffffffffffffffffffff8516600090815260226020526040902080548290811061410757614107614d4d565b90600052602060002090600502016040518060a001604052908160008201548152602001600182015481526020016002820154815260200160038201548152602001600482015481525050925080915061416e565b8061416681614e52565b915050614054565b50815183146141d9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f5374616b65206e6f7420666f756e6400000000000000000000000000000000006044820152606401610c40565b9250929050565b6040805173ffffffffffffffffffffffffffffffffffffffff85811660248301528481166044830152606480830185905283518084039091018152608490920183526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f23b872dd00000000000000000000000000000000000000000000000000000000179052915160009283929088169161427f9190614f4b565b6000604051808303816000865af19150503d80600081146142bc576040519150601f19603f3d011682016040523d82523d6000602084013e6142c1565b606091505b50915091508180156142eb5750805115806142eb5750808060200190518101906142eb9190614f67565b614376576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f5472616e7366657248656c7065723a205452414e534645525f46524f4d5f464160448201527f494c4544000000000000000000000000000000000000000000000000000000006064820152608401610c40565b505050505050565b600061438c84846001613be6565b5060008061439a868561401b565b915091508160600151421015806143b8575060215460ff1615156001145b61441e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f5374616b65206973207374696c6c206c6f636b656421000000000000000000006044820152606401610c40565b604082015180156145d5576144547f00000000000000000000000003b59bd1c8b9f6c265ba0c3421923b93f15036fa8783613eb2565b80601b60008282546144669190614dab565b909155505073ffffffffffffffffffffffffffffffffffffffff87166000908152601d6020526040812080548392906144a0908490614dab565b90915550600090506144b188612496565b905073ffffffffffffffffffffffffffffffffffffffff81161561450a5773ffffffffffffffffffffffffffffffffffffffff81166000908152601f602052604081208054849290614504908490614dab565b90915550505b5073ffffffffffffffffffffffffffffffffffffffff8716600090815260226020526040902080548390811061454257614542614d4d565b60009182526020822060059091020181815560018101829055600281018290556003810182905560040181905561457a908890611374565b604080518281526020810187905273ffffffffffffffffffffffffffffffffffffffff888116828401529151918916917f1d9308f6b22a2754a1c622bb30889e8f8f956c83e524d039e9d65d5f052eb9089181900360600190a25b9695505050505050565b60005b6012548110156146d05760006012828154811061460157614601614d4d565b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff16905080156146bd576040517f092193ab00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff82169063092193ab9060240160408051808303816000875af1158015614696573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906146ba9190614f84565b50505b50806146c881614e52565b9150506145e2565b50600062093a80600454426146e59190614dab565b6146ef9190614dff565b905060005b6010548110156148d2576010818154811061471157614711614d4d565b6000918252602090912001546040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff909116906370a0823190602401602060405180830381865afa158015614788573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906147ac9190614e8a565b6147b7836001614e3a565b62093a806147c4846131dc565b6147ce9190614dc2565b6147d89190614dc2565b1115601082815481106147ed576147ed614d4d565b60009182526020918290200154604080517f4e6f7420656e6f7567682072657761726420746f6b656e7320617661696c6162938101939093527f6c653a20000000000000000000000000000000000000000000000000000000009083015260601b7fffffffffffffffffffffffffffffffffffffffff000000000000000000000000166044820152605801604051602081830303815290604052906148bf576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c409190614fa8565b50806148ca81614e52565b9150506146f4565b5062093a806148e2826001614e3a565b6148ec9190614dc2565b6004546148f99190614e3a565b600455614904614912565b61490c611498565b60035550565b600061491c611638565b905060005b6015548110156149765781818151811061493d5761493d614d4d565b60200260200101516015828154811061495857614958614d4d565b6000918252602090912001558061496e81614e52565b915050614921565b5061497f613bd3565b60055550565b803573ffffffffffffffffffffffffffffffffffffffff811681146124f357600080fd5b6000602082840312156149bb57600080fd5b6136c682614985565b6020808252825182820181905260009190848201906040850190845b818110156149fc578351835292840192918401916001016149e0565b50909695505050505050565b600060208284031215614a1a57600080fd5b5035919050565b6020808252825182820181905260009190848201906040850190845b818110156149fc57835173ffffffffffffffffffffffffffffffffffffffff1683529284019291840191600101614a3d565b60008060408385031215614a8257600080fd5b50508035926020909101359150565b602080825282518282018190526000919060409081850190868401855b82811015614af25781518051855286810151878601528581015186860152606080820151908601526080908101519085015260a09093019290850190600101614aae565b5091979650505050505050565b60008060408385031215614b1257600080fd5b614b1b83614985565b9150614b2960208401614985565b90509250929050565b80151581146131d957600080fd5b60008060408385031215614b5357600080fd5b614b5c83614985565b91506020830135614b6c81614b32565b809150509250929050565b60008060408385031215614b8a57600080fd5b614b9383614985565b946020939093013593505050565b600080600060608486031215614bb657600080fd5b8335614bc181614b32565b92506020840135614bd181614b32565b91506040840135614be181614b32565b809150509250925092565b60008060008060808587031215614c0257600080fd5b614c0b85614985565b935060208501359250614c2060408601614985565b9150614c2e60608601614985565b905092959194509250565b60008060408385031215614c4c57600080fd5b82359150614b2960208401614985565b600060208284031215614c6e57600080fd5b81356136c681614b32565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600060c08284031215614cba57600080fd5b82601f830112614cc957600080fd5b60405160c0810181811067ffffffffffffffff82111715614d13577f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040528060c0840185811115614d2857600080fd5b845b81811015614d42578035835260209283019201614d2a565b509195945050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600082821015614dbd57614dbd614d7c565b500390565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615614dfa57614dfa614d7c565b500290565b600082614e35577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b60008219821115614e4d57614e4d614d7c565b500190565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203614e8357614e83614d7c565b5060010190565b600060208284031215614e9c57600080fd5b5051919050565b80516dffffffffffffffffffffffffffff811681146124f357600080fd5b600080600080600060a08688031215614ed957600080fd5b614ee286614ea3565b9450614ef060208701614ea3565b935060408601519250614f0560608701614ea3565b9150614f1360808701614ea3565b90509295509295909350565b60005b83811015614f3a578181015183820152602001614f22565b83811115611d4b5750506000910152565b60008251614f5d818460208701614f1f565b9190910192915050565b600060208284031215614f7957600080fd5b81516136c681614b32565b60008060408385031215614f9757600080fd5b505080516020909101519092909150565b6020815260008251806020840152614fc7816040850160208701614f1f565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016919091016040019291505056fea2646970667358221220d1bcf14daa5da273eb104d6a8414d0641f8933549ff1680562afa0fd13d7084664736f6c634300080f0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000ff5b4bcbf765fe363269114e1c765229a29edefd00000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000000000000001a000000000000000000000000000000000000000000000000000000000000001e000000000000000000000000003b59bd1c8b9f6c265ba0c3421923b93f15036fa00000000000000000000000000000000000000000000000000000000000000010000000000000000000000003432b6a60d23ca0dfca7761b7ab56459d9c964d00000000000000000000000000000000000000000000000000000000000000001000000000000000000000000b1748c79709f4ba2dd82834b8c82d4a505003f27000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000a86cc92e3da000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000278dc748eda1d8efef1adfb518542612b49fcd34
-----Decoded View---------------
Arg [0] : _owner (address): 0xfF5B4BCbf765FE363269114e1c765229a29eDeFD
Arg [1] : _rewardTokens (address[]): 0x3432B6A60D23Ca0dFCa7761B7ab56459D9C964D0
Arg [2] : _rewardManagers (address[]): 0xB1748C79709f4Ba2Dd82834B8c82D4a505003f27
Arg [3] : _rewardRates (uint256[]): 11574074074074
Arg [4] : _gaugeControllers (address[]): 0x0000000000000000000000000000000000000000
Arg [5] : _rewardDistributors (address[]): 0x278dC748edA1d8eFEf1aDFB518542612b49Fcd34
Arg [6] : _stakingToken (address): 0x03B59Bd1c8B9F6C265bA0c3421923B93f15036Fa
-----Encoded View---------------
17 Constructor Arguments found :
Arg [0] : 000000000000000000000000ff5b4bcbf765fe363269114e1c765229a29edefd
Arg [1] : 00000000000000000000000000000000000000000000000000000000000000e0
Arg [2] : 0000000000000000000000000000000000000000000000000000000000000120
Arg [3] : 0000000000000000000000000000000000000000000000000000000000000160
Arg [4] : 00000000000000000000000000000000000000000000000000000000000001a0
Arg [5] : 00000000000000000000000000000000000000000000000000000000000001e0
Arg [6] : 00000000000000000000000003b59bd1c8b9f6c265ba0c3421923b93f15036fa
Arg [7] : 0000000000000000000000000000000000000000000000000000000000000001
Arg [8] : 0000000000000000000000003432b6a60d23ca0dfca7761b7ab56459d9c964d0
Arg [9] : 0000000000000000000000000000000000000000000000000000000000000001
Arg [10] : 000000000000000000000000b1748c79709f4ba2dd82834b8c82d4a505003f27
Arg [11] : 0000000000000000000000000000000000000000000000000000000000000001
Arg [12] : 00000000000000000000000000000000000000000000000000000a86cc92e3da
Arg [13] : 0000000000000000000000000000000000000000000000000000000000000001
Arg [14] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [15] : 0000000000000000000000000000000000000000000000000000000000000001
Arg [16] : 000000000000000000000000278dc748eda1d8efef1adfb518542612b49fcd34
Deployed Bytecode Sourcemap
87676:524:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;35332:529;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;37542:477;;;;;;:::i;:::-;;:::i;:::-;;;1374:25:1;;;1362:2;1347:18;37542:477:0;1228:177:1;33611:109:0;;;:::i;:::-;;;;;;;:::i;22957:141::-;;;;;;:::i;:::-;;:::i;:::-;;82653:190;;;;;;:::i;:::-;;:::i;35925:339::-;;;:::i;77908:133::-;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;38238:179::-;;;;;;:::i;:::-;;:::i;33275:298::-;;;;;;:::i;:::-;;:::i;:::-;;;3977:14:1;;3970:22;3952:41;;3940:2;3925:18;33275:298:0;3812:187:1;30651:60:0;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;4180:42:1;4168:55;;;4150:74;;4138:2;4123:18;30651:60:0;4004:226:1;39786:1752:0;;;;;;:::i;:::-;;:::i;36978:127::-;;;;;;:::i;:::-;37071:26;;37044:7;37071:26;;;:17;:26;;;;;;;36978:127;29591:48;;29633:6;29591:48;;45653:238;;;;;;:::i;:::-;;:::i;29219:49::-;;;;;;:::i;:::-;;;;;;;;;;;;;;;;38938:181;;;;;;:::i;:::-;;:::i;22725:29::-;;;;;;;;;43487:1522;;;;;;:::i;:::-;;:::i;69529:3516::-;;;:::i;36692:111::-;36773:22;;36692:111;;29472:55;;;;;;:::i;:::-;;;;;;;;;;;;;;29983:54;;;;;;:::i;:::-;;;;;;;;;;;;;;28493:37;;;;;;34435:681;;;:::i;66295:43::-;;;;;73099:2692;;;;;;:::i;:::-;;:::i;46360:206::-;;;;;;:::i;:::-;;:::i;66868:53::-;;;;;;:::i;:::-;;:::i;:::-;;;;5449:25:1;;;5505:2;5490:18;;5483:34;;;;5533:18;;;5526:34;;;;5591:2;5576:18;;5569:34;5634:3;5619:19;;5612:35;5436:3;5421:19;66868:53:0;5190:463:1;23106:271:0;;;:::i;30442:52::-;;;;;;:::i;:::-;;;;;;;;;;;;;;39127:199;;;;;;:::i;:::-;;:::i;53358:1013::-;;;;;;:::i;:::-;;:::i;75852:1961::-;;;;;;:::i;:::-;;:::i;:::-;;;;5860:25:1;;;5916:2;5901:18;;5894:34;;;;5944:18;;;5937:34;5848:2;5833:18;75852:1961:0;5658:319:1;22698:20:0;;;;;;;;;53068:161;;;;;;:::i;:::-;;:::i;30842:26::-;;;;;;;;;38520:224;;;;;;:::i;:::-;;:::i;28587:55::-;;;;;;79782:1325;;;;;;:::i;:::-;;:::i;28340:61::-;;;;;;46180:172;;;;;;:::i;:::-;;:::i;39334:444::-;;;;;;:::i;:::-;;:::i;28186:29::-;;;;;;78117:133;;;;;;:::i;:::-;78214:21;;78187:7;78214:21;;;:12;:21;;;;;:28;;78117:133;52518:311;;;;;;:::i;:::-;;:::i;28266:50::-;;;;;;27989:30;;;;;;81161:1357;;;;;;:::i;:::-;;:::i;38064:166::-;;;;;;:::i;:::-;;:::i;55414:483::-;;;;;;:::i;:::-;;:::i;42521:800::-;;;;;;:::i;:::-;;:::i;36526:128::-;;;;;;:::i;:::-;36620:26;;36593:7;36620:26;;;:17;:26;;;;;;;36526:128;55972:207;;;;;;:::i;:::-;;:::i;36362:113::-;36444:23;;36362:113;;52922:97;;;:::i;84916:259::-;;;;;;:::i;:::-;;:::i;41796:610::-;;;;;;:::i;:::-;;:::i;28152:27::-;;;;;;28725:51;;;;;;28801:59;;;;;;33913:452;;;;;;:::i;:::-;;:::i;51208:761::-;;;;;;:::i;:::-;;:::i;54379:958::-;;;;;;:::i;:::-;;:::i;51977:363::-;;;:::i;35332:529::-;35386:27;35426;35456:17;:15;:17::i;:::-;35511:12;:19;35426:47;;-1:-1:-1;35497:34:0;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;35497:34:0;-1:-1:-1;35548:26:0;;;35577:1;35548:26;;;:17;:26;;;;;;35484:47;;-1:-1:-1;35548:30:0;35544:310;;35599:9;35594:249;35618:12;:19;35614:23;;35594:249;;;35808:16;;;;;;;:7;:16;;;;;;;;:19;;;;;;;;;35727:32;;;:23;:32;;;;;:35;;;;;;;;;35711:13;;35767:4;;35727:35;35711:10;;35825:1;;35711:13;;;;;;:::i;:::-;;;;;;;:51;;;;:::i;:::-;35681:26;;;;;;;:17;:26;;;;;;:82;;;;:::i;:::-;35680:91;;;;:::i;:::-;35679:148;;;;:::i;:::-;35663:10;35674:1;35663:13;;;;;;;;:::i;:::-;;;;;;;;;;:164;35639:3;;;;:::i;:::-;;;;35594:249;;;;35544:310;35415:446;35332:529;;;:::o;37542:477::-;37906:19;;37971:28;;37601:7;;37883:127;;37941:26;37906:19;37941:4;:26;:::i;:::-;37940:59;;;;:::i;:::-;37883:8;:127::i;:::-;37876:134;37542:477;-1:-1:-1;;37542:477:0:o;33611:109::-;33664:16;33700:12;33693:19;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;33611:109;:::o;22957:141::-;23437:5;;;;23423:10;:19;23415:79;;;;;;;10328:2:1;23415:79:0;;;10310:21:1;10367:2;10347:18;;;10340:30;10406:34;10386:18;;;10379:62;10477:17;10457:18;;;10450:45;10512:19;;23415:79:0;;;;;;;;;23029:14:::1;:23:::0;;;::::1;;::::0;::::1;::::0;;::::1;::::0;;;23068:22:::1;::::0;4150:74:1;;;23068:22:0::1;::::0;4138:2:1;4123:18;23068:22:0::1;;;;;;;22957:141:::0;:::o;82653:190::-;82738:7;21632:1;22238:7;;:19;22230:63;;;;;;;10744:2:1;22230:63:0;;;10726:21:1;10783:2;10763:18;;;10756:30;10822:33;10802:18;;;10795:61;10873:18;;22230:63:0;10542:355:1;22230:63:0;21632:1;22371:18;;82765:70:::1;82778:10;::::0;82802:9;82813:4;82819:15:::1;82765:12;:70::i;:::-;21588:1:::0;22550:7;:22;82758:77;82653:190;-1:-1:-1;;;82653:190:0:o;35925:339::-;36075:17;:24;35980:41;;36061:39;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;36061:39:0;;36034:66;;36118:9;36113:144;36137:17;:24;36133:28;;36113:144;;;29633:6;36213:14;36225:1;36213:11;:14::i;:::-;:32;;;;:::i;:::-;36183:24;36208:1;36183:27;;;;;;;;:::i;:::-;;;;;;;;;;:62;36163:3;;;;:::i;:::-;;;;36113:144;;;;35925:339;:::o;77908:133::-;78012:21;;;;;;;:12;:21;;;;;;;;78005:28;;;;;;;;;;;;;;;;;77972:20;;78005:28;;78012:21;;78005:28;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;77908:133;;;:::o;38238:179::-;38353:32;;;38307:7;38353:32;;;:17;:32;;;;;;38335:15;;28117:4;;38335:50;;;:::i;:::-;38334:75;;;;:::i;33275:298::-;33371:4;33406:5;;;;;;33391:20;;;;33387:136;;-1:-1:-1;33420:4:0;33413:11;;33387:136;33462:48;:33;;;;;;;:14;:33;;;;;;:48;;;:33;;:48;33458:65;;-1:-1:-1;33519:4:0;33512:11;;33458:65;-1:-1:-1;33559:5:0;33275:298;;;;:::o;39786:1752::-;39849:24;;;40010:20;40022:7;40010:11;:20::i;:::-;39990:40;-1:-1:-1;40061:23:0;;;;40060:81;;40115:26;;;;;:15;4168:55:1;;;40115:26:0;;;4150:74:1;40115:5:0;:15;;;;4123:18:1;;40115:26:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;40060:81;;;40088:24;;;;;:15;4168:55:1;;;40088:24:0;;;4150:74:1;40088:5:0;:15;;;;4123:18:1;;40088:24:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;40041:100;;40247:19;28117:4;40371:5;:17;;;:19;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:42;;;;:::i;:::-;40312:24;;40289:20;;40270:39;;:16;:39;:::i;:::-;:66;;;;:::i;:::-;40269:145;;;;:::i;:::-;40247:167;-1:-1:-1;40523:19:0;;40738:23;;;;40737:94;;40796:35;40821:9;40796:24;:35::i;:::-;40737:94;;;40765:28;40785:7;40765:19;:28::i;:::-;40708:123;-1:-1:-1;40852:30:0;;40848:323;;40903:27;40977:26;40934:39;28117:4;40934:16;:39;:::i;:::-;40933:70;;;;:::i;:::-;40903:100;;28117:4;41077:20;;41055:19;:42;;;;:::i;:::-;41054:67;;;;:::i;:::-;41040:81;;40883:254;40848:323;;;41170:1;41156:15;;40848:323;40553:699;41339:11;41325;:25;:53;;41367:11;41325:53;;;41353:11;41325:53;41305:74;;41469:20;;41450:16;:39;41446:84;;;41510:20;;41491:39;;41446:84;39875:1663;;;;39786:1752;;;:::o;45653:238::-;21632:1;22238:7;;:19;22230:63;;;;;;;10744:2:1;22230:63:0;;;10726:21:1;10783:2;10763:18;;;10756:30;10822:33;10802:18;;;10795:61;10873:18;;22230:63:0;10542:355:1;22230:63:0;21632:1;22371:18;;45750:23:::1;::::0;;;::::1;;;:32;45742:70;;;::::0;::::1;::::0;;11293:2:1;45742:70:0::1;::::0;::::1;11275:21:1::0;11332:2;11312:18;;;11305:30;11371:27;11351:18;;;11344:55;11416:18;;45742:70:0::1;11091:349:1::0;45742:70:0::1;-1:-1:-1::0;21588:1:0;22550:7;:22;45653:238::o;38938:181::-;39005:7;28117:4;39059:28;;39033:23;39048:7;39033:14;:23::i;:::-;:54;;;;:::i;43487:1522::-;43674:8;43670:46;;;43698:6;:4;:6::i;:::-;43740:21;;;;43736:1266;;43954:27;44000:28;44047:27;44092:30;44114:7;44092:21;:30::i;:::-;43932:190;;;;;;44184:20;44196:7;44184:11;:20::i;:::-;44280:31;;;;;;;:22;:31;;;;;:54;;;44421:42;;;44417:572;;44484:19;44506:41;44528:19;44506;:41;:::i;:::-;44484:63;;44616:11;44591:22;;:36;;;;:::i;:::-;44566:22;:61;44675:33;44697:11;44675:19;:33;:::i;:::-;44646:26;;;;;;;:17;:26;;;;;:62;-1:-1:-1;44417:572:0;;;44749:19;44771:41;44793:19;44771;:41;:::i;:::-;44749:63;;44881:11;44856:22;;:36;;;;:::i;:::-;44831:22;:61;44940:33;44962:11;44940:19;:33;:::i;:::-;44911:26;;;;;;;:17;:26;;;;;:62;-1:-1:-1;44417:572:0;43763:1239;;;43736:1266;43487:1522;;:::o;69529:3516::-;69585:7;69666:25;70465:27;70508:17;70527;70554:12;:33;;;70588:15;70554:50;;;;;;;;;;;;;1374:25:1;;1362:2;1347:18;;1228:177;70554:50:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;70507:98;;;;;;;;;;;70624:14;;;;;;;;;;;70620:102;;;70662:9;70640:31;;70620:102;;;70713:9;70691:31;;70620:102;70790:12;:24;;;:26;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;70760;:19;70782:4;70760:26;:::i;:::-;70759:57;;;;:::i;:::-;70739:77;69529:3516;-1:-1:-1;;;;;69529:3516:0:o;34435:681::-;34483:41;34541:23;;34568:1;34541:28;:59;;;-1:-1:-1;34573:22:0;;:27;34541:59;34537:572;;;34624:21;34617:28;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;34435:681;:::o;34537:572::-;34728:12;:19;34714:34;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;34714:34:0;;34687:61;;34768:9;34763:289;34787:21;:28;34783:32;;34763:289;;;34995:22;;34970:14;34982:1;34970:11;:14::i;:::-;34952;;34923:26;:24;:26::i;:::-;:43;;;;:::i;:::-;34922:62;;;;:::i;:::-;:69;;34987:4;34922:69;:::i;:::-;34921:96;;;;:::i;:::-;34871:21;34893:1;34871:24;;;;;;;;:::i;:::-;;;;;;;;;:165;;;;:::i;:::-;34841:24;34866:1;34841:27;;;;;;;;:::i;:::-;;;;;;;;;;:195;34817:3;;;;:::i;:::-;;;;34763:289;;73099:2692;73290:21;;;73188:32;73290:21;;;:12;:21;;;;;:32;;73188;;73290:21;73312:9;;73290:32;;;;;;:::i;:::-;;;;;;;;;73259:63;;;;;;;;73290:32;;;;;;;73259:63;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;73505:28;;;;;:19;:28;;;;;;73259:63;;-1:-1:-1;;73501:224:0;;;-1:-1:-1;73598:25:0;;;;73501:224;;;-1:-1:-1;73685:28:0;;;;;;;:19;:28;;;;;;73501:224;73814:15;73784:9;:26;;;:45;73780:1802;;74009:26;;;;73978:28;;;;;;;:19;:28;;;;;;:57;73974:1087;;;74055:26;74113:17;74084:9;:26;;;:46;;;;:::i;:::-;74055:75;;74149:25;74195:9;:26;;;74177:15;:44;;;;:::i;:::-;74149:72;-1:-1:-1;74301:33:0;74337:38;74352:22;74373:1;74352:18;:22;:::i;74337:38::-;74301:74;-1:-1:-1;74592:17:0;74664:21;74668:17;74592;74664:21;:::i;:::-;74613:46;74641:18;74613:25;:46;:::i;:::-;74612:74;;;;:::i;:::-;74592:94;-1:-1:-1;74745:38:0;74766:17;74745:18;:38;:::i;:::-;74732:52;;:9;:52;:::i;:::-;74705:79;;74036:764;;;;73780:1802;;73974:1087;75044:1;75017:28;;73780:1802;;;75206:21;75261:20;75313:17;75284:9;:26;;;:46;;;;:::i;:::-;75261:69;;75349:20;75401:15;75372:9;:26;;;:44;;;;:::i;:::-;75349:67;-1:-1:-1;75483:1:0;75452:27;75349:67;75452:12;:27;:::i;:::-;75451:33;;;;:::i;:::-;75435:49;;75242:258;;75541:29;75556:13;75541:14;:29::i;:::-;75514:56;;75126:456;73780:1802;75704:9;:25;;;75677:24;:52;75673:110;;;75758:9;:25;;;75731:52;;75673:110;73222:2569;;73099:2692;;;;:::o;46360:206::-;46462:16;21632:1;22238:7;;:19;22230:63;;;;;;;10744:2:1;22230:63:0;;;10726:21:1;10783:2;10763:18;;;10756:30;10822:33;10802:18;;;10795:61;10873:18;;22230:63:0;10542:355:1;22230:63:0;21632:1;22371:18;;46498:60:::1;46509:10;46521:19:::0;46542:15;46498:10:::1;:60::i;66868:53::-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;66868:53:0;;-1:-1:-1;66868:53:0;;;:::o;23106:271::-;23175:14;;;;23161:10;:28;23153:94;;;;;;;12371:2:1;23153:94:0;;;12353:21:1;12410:2;12390:18;;;12383:30;12449:34;12429:18;;;12422:62;12520:23;12500:18;;;12493:51;12561:19;;23153:94:0;12169:417:1;23153:94:0;23276:5;;;23283:14;23263:35;;;23276:5;;;;12826:34:1;;23283:14:0;;;;12891:2:1;12876:18;;12869:43;23263:35:0;;12738:18:1;23263:35:0;;;;;;;23317:14;;;;23309:22;;;;;;23317:14;;;23309:22;;;;23342:27;;;23106:271::o;39127:199::-;39205:7;28117:4;39266:28;;39233:30;39249:13;39233:15;:30::i;53358:1013::-;31469:5;;53444:12;;31469:5;;31455:10;:19;;:74;;;31478:51;31496:10;31508:20;31478:17;:51::i;:::-;31447:107;;;;;;;13125:2:1;31447:107:0;;;13107:21:1;13164:2;13144:18;;;13137:30;13203:22;13183:18;;;13176:50;13243:18;;31447:107:0;12923:344:1;31447:107:0;53526:18:::1;53568:9:::0;53563:192:::1;53587:12;:19:::0;53583:23;::::1;53563:192;;;53651:12;53632:31;;:12;53645:1;53632:15;;;;;;;;:::i;:::-;;::::0;;;::::1;::::0;;;::::1;::::0;::::1;;:31:::0;53628:116:::1;;53700:4;53684:20;;53723:5;;53628:116;53608:3:::0;::::1;::::0;::::1;:::i;:::-;;;;53563:192;;;;53981:13;:59;;;;-1:-1:-1::0;53998:42:0::1;:28:::0;;::::1;;::::0;;;:14:::1;:28;::::0;;;;;::::1;54030:10;53998:42;53981:59;53980:123;;;;54064:13;54063:14;:39;;;;-1:-1:-1::0;54096:5:0::1;::::0;::::1;;54082:10;:19;54063:39;53958:406;;;54134:66;54162:12;54176:10;54188:11;54134:27;:66::i;:::-;54215:7;53358:1013:::0;;;:::o;53958:406::-:1;54316:36;::::0;::::1;::::0;;13474:2:1;54316:36:0::1;::::0;::::1;13456:21:1::0;13513:2;13493:18;;;13486:30;13552:28;13532:18;;;13525:56;13598:18;;54316:36:0::1;13272:350:1::0;31565:1:0::1;53358:1013:::0;;;:::o;75852:1961::-;76155:26;;;75953:27;76155:26;;;:17;:26;;;;;;;75953:27;76342:24;76173:7;76342:15;:24::i;:::-;76442:26;;;76379:33;76442:26;;;:17;:26;;;;;;76319:47;;-1:-1:-1;76379:33:0;76442:31;:66;;;;-1:-1:-1;76477:26:0;;;;;;;:17;:26;;;;;;:31;76442:66;76441:143;;;-1:-1:-1;76552:31:0;;;;;;;:22;:31;;;;;;76528:55;;;76441:143;76423:638;;;-1:-1:-1;76825:20:0;76423:638;;;77013:31;;;;;;;:22;:31;;;;;;77048:1;;76990:54;;:20;:54;:::i;:::-;76989:60;;;;:::i;:::-;76961:88;;76423:638;77196:1;77174:23;;77213:9;77208:598;77232:21;;;;;;;:12;:21;;;;;:28;77228:32;;77208:598;;;77313:21;;;77282:28;77313:21;;;:12;:21;;;;;:24;;77335:1;;77313:24;;;;;;:::i;:::-;;;;;;;;;;;77282:55;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;77409:32;77444:34;77467:7;77476:1;77444:22;:34::i;:::-;77560:19;;;;77409:69;;-1:-1:-1;77540:17:0;28117:4;77655:52;77682:25;77409:69;77655:52;:::i;:::-;77642:66;;:9;:66;:::i;:::-;77641:91;;;;:::i;:::-;77628:105;;:9;:105;:::i;:::-;77594:139;-1:-1:-1;77748:46:0;77594:139;77748:46;;:::i;:::-;;;77267:539;;;;77262:3;;;;;:::i;:::-;;;;77208:598;;;;76082:1731;75852:1961;;;;;:::o;53068:161::-;31266:5;;;;31252:10;:19;;:79;;-1:-1:-1;31289:42:0;31275:10;:56;31252:79;31244:113;;;;;;;13829:2:1;31244:113:0;;;13811:21:1;13868:2;13848:18;;;13841:30;13907:23;13887:18;;;13880:51;13948:18;;31244:113:0;13627:345:1;31244:113:0;53189:32:::1;;;::::0;;;:19:::1;:32;::::0;;;;;;53153:68;;::::1;53189:32;::::0;;::::1;53188:33;53153:68;::::0;;53068:161::o;38520:224::-;38586:7;38720:15;;38689:28;;:46;;;;:::i;:::-;38614:24;;;;;:15;4168:55:1;;;38614:24:0;;;4150:74:1;28117:4:0;;;;38614:5;:15;;;;4123:18:1;;38614:24:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:47;;;;:::i;79782:1325::-;21632:1;22238:7;;:19;22230:63;;;;;;;10744:2:1;22230:63:0;;;10726:21:1;10783:2;10763:18;;;10756:30;10822:33;10802:18;;;10795:61;10873:18;;22230:63:0;10542:355:1;22230:63:0;21632:1;22371:18;;79879:10:::1;79891:4;31660:41;79879:10:::0;79891:4;31660:22:::1;:41::i;:::-;79956:28:::2;79986:21:::0;80011:29:::2;80021:10;80033:6;80011:9;:29::i;:::-;79955:85;;;;80090:15;80130:8;80108:9;:19;;;:30;;;;:::i;:::-;80090:48:::0;-1:-1:-1;80269:91:0::2;80309:12;80324:10;80344:4;80351:8;80269:31;:91::i;:::-;80444:186;::::0;;::::2;::::0;::::2;::::0;;;;;::::2;80491:25:::0;;::::2;::::0;80444:186;;::::2;::::0;;;;;;;;80553:26;;::::2;::::0;80444:186;;;;;80594:25;;::::2;::::0;80444:186;;;;80415:10:::2;-1:-1:-1::0;80402:24:0;;;:12:::2;:24:::0;;;;;;;:39;;80427:13;;80402:39;::::2;;;;;:::i;:::-;;;;;;;;;;;:228;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;80701:8;80674:23;;:35;;;;;;;:::i;:::-;::::0;;;-1:-1:-1;;80738:10:0::2;80720:29;::::0;;;:17:::2;:29;::::0;;;;:41;;80753:8;;80720:29;:41:::2;::::0;80753:8;;80720:41:::2;:::i;:::-;::::0;;;-1:-1:-1;80787:17:0::2;::::0;-1:-1:-1;80807:23:0::2;80819:10;80807:11;:23::i;:::-;80787:43:::0;-1:-1:-1;80849:23:0::2;::::0;::::2;::::0;80845:69:::2;;80874:28;::::0;::::2;;::::0;;;:17:::2;:28;::::0;;;;:40;;80906:8;;80874:28;:40:::2;::::0;80906:8;;80874:40:::2;:::i;:::-;::::0;;;-1:-1:-1;;80845:69:0::2;80772:154;80994:41;81017:10;81029:5;80994:22;:41::i;:::-;81053:46;::::0;;14496:25:1;;;14552:2;14537:18;;14530:34;;;81070:10:0::2;::::0;81053:46:::2;::::0;14469:18:1;81053:46:0::2;;;;;;;-1:-1:-1::0;;21588:1:0;22550:7;:22;-1:-1:-1;;;;;79782:1325:0:o;46180:172::-;46259:16;21632:1;22238:7;;:19;22230:63;;;;;;;10744:2:1;22230:63:0;;;10726:21:1;10783:2;10763:18;;;10756:30;10822:33;10802:18;;;10795:61;10873:18;;22230:63:0;10542:355:1;22230:63:0;21632:1;22371:18;;46295:49:::1;46306:10;46318:19:::0;46339:4:::1;46295:10;:49::i;:::-;21588:1:::0;22550:7;:22;46288:56;46180:172;-1:-1:-1;;46180:172:0:o;39334:444::-;39413:25;;;39390:7;39413:25;;;:19;:25;;;;;;;;39409:362;;;-1:-1:-1;39616:4:0;39334:444::o;39409:362::-;-1:-1:-1;39728:31:0;;;;;;;;:25;:31;;;;;;;;39334:444::o;39409:362::-;39334:444;;;:::o;52518:311::-;31266:5;;;;31252:10;:19;;:79;;-1:-1:-1;31289:42:0;31275:10;:56;31252:79;31244:113;;;;;;;13829:2:1;31244:113:0;;;13811:21:1;13868:2;13848:18;;;13841:30;13907:23;13887:18;;;13880:51;13948:18;;31244:113:0;13627:345:1;31244:113:0;52681:13:::1;:30:::0;;52771:50;::::1;;::::0;::::1;::::0;52722:38;::::1;;52681:30;52722:38;::::0;52681:30;::::1;;::::0;::::1;52722:38:::0;;;;;;;;;;;;;;;::::1;52771:50:::0;;;::::1;;::::0;;52518:311::o;81161:1357::-;21632:1;22238:7;;:19;22230:63;;;;;;;10744:2:1;22230:63:0;;;10726:21:1;10783:2;10763:18;;;10756:30;10822:33;10802:18;;;10795:61;10873:18;;22230:63:0;10542:355:1;22230:63:0;21632:1;22371:18;;81259:10:::1;81271:4;31660:41;81259:10:::0;81271:4;31660:22:::1;:41::i;:::-;81336:28:::2;81366:21:::0;81391:29:::2;81401:10;81413:6;81391:9;:29::i;:::-;81335:85;;;;81475:15;81459:13;:31;81451:65;;;::::0;::::2;::::0;;14777:2:1;81451:65:0::2;::::0;::::2;14759:21:1::0;14816:2;14796:18;;;14789:30;14855:23;14835:18;;;14828:51;14896:18;;81451:65:0::2;14575:345:1::0;81451:65:0::2;81562:17;81612:15;81583:9;:26;;;:44;81582:97;;81678:1;81582:97;;;81660:15;81631:9;:26;;;:44;;;;:::i;:::-;81562:117:::0;-1:-1:-1;81690:16:0::2;81709:31;81725:15;81709:13:::0;:31:::2;:::i;:::-;81690:50;;81846:9;81835:8;:20;81827:57;;;::::0;::::2;::::0;;15127:2:1;81827:57:0::2;::::0;::::2;15109:21:1::0;15166:2;15146:18;;;15139:30;15205:26;15185:18;;;15178:54;15249:18;;81827:57:0::2;14925:348:1::0;81827:57:0::2;81915:13;;81903:8;:25;;81895:64;;;::::0;::::2;::::0;;15480:2:1;81895:64:0::2;::::0;::::2;15462:21:1::0;15519:2;15499:18;;;15492:30;15558:28;15538:18;;;15531:56;15604:18;;81895:64:0::2;15278:350:1::0;81895:64:0::2;81990:28;;81978:8;:40;;81970:80;;;::::0;::::2;::::0;;15835:2:1;81970:80:0::2;::::0;::::2;15817:21:1::0;15874:2;15854:18;;;15847:30;15913:29;15893:18;;;15886:57;15960:18;;81970:80:0::2;15633:351:1::0;81970:80:0::2;82134:174;;;;;;;;82160:6;82134:174;;;;82181:15;82134:174;;;;82211:9;:19;;;82134:174;;;;82245:13;82134:174;;;;82273:24;82288:8;82273:14;:24::i;:::-;82134:174:::0;;82105:10:::2;82092:24;::::0;;;:12:::2;:24;::::0;;;;:39;;82117:13;;82092:39;::::2;;;;;:::i;:::-;;;;;;;;;;;:216;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;82377:41;82400:10;82412:5;82377:22;:41::i;:::-;82436:74;::::0;;16220:25:1;;;16276:2;16261:18;;16254:34;;;82479:15:0::2;16304:18:1::0;;;16297:34;16362:2;16347:18;;16340:34;;;82436:74:0;;82449:10:::2;::::0;82436:74:::2;::::0;;;;;16207:3:1;82436:74:0;;::::2;-1:-1:-1::0;;21588:1:0;22550:7;:22;-1:-1:-1;;;;;;81161:1357:0:o;38064:166::-;38172:26;;;38126:7;38172:26;;;:17;:26;;;;;;38154:15;;28117:4;;38154:44;;;:::i;55414:483::-;31469:5;;55580:20;;31469:5;;31455:10;:19;;:74;;;31478:51;31496:10;31508:20;31478:17;:51::i;:::-;31447:107;;;;;;;13125:2:1;31447:107:0;;;13107:21:1;13164:2;13144:18;;;13137:30;13203:22;13183:18;;;13176:50;13243:18;;31447:107:0;12923:344:1;31447:107:0;55631:42:::1;::::0;::::1;;::::0;;;:20:::1;:42;::::0;;;;;55613:17:::1;:61:::0;;55677:9;;55631:42;55613:61;::::1;;;;;:::i;:::-;;;;;;;;:73;;;;55760:25;55697:16;55714:20;:42;55735:20;55714:42;;;;;;;;;;;;;;;;55697:60;;;;;;;;:::i;:::-;;::::0;;;::::1;::::0;;;;;;::::1;:88:::0;;;::::1;;::::0;;::::1;;::::0;;55815:42;;::::1;::::0;;:20:::1;:42:::0;;;;;;;55796:18:::1;:62:::0;;55861:28;;55815:42;55796:62;::::1;;;;;:::i;:::-;;;;;;;;;:93;;;;;;;;;;;;;;;;;;55414:483:::0;;;;;:::o;42521:800::-;42601:34;;;;;;;:19;:34;;;;;;;;42593:60;;;;;;;16587:2:1;42593:60:0;;;16569:21:1;16626:2;16606:18;;;16599:30;16665:15;16645:18;;;16638:43;16698:18;;42593:60:0;16385:337:1;42593:60:0;42672:36;;;;;;;:21;:36;;;;;;;;42709:10;42672:48;;;;;;;;;;42664:90;;;;;;;16929:2:1;42664:90:0;;;16911:21:1;16968:2;16948:18;;;16941:30;17007:31;16987:18;;;16980:59;17056:18;;42664:90:0;16727:353:1;42664:90:0;42900:10;42849:22;42874:37;;;:25;:37;;;;;;;;42926:28;;42922:182;;43081:10;43063:29;;;;:17;:29;;;;;;;;;;43026:33;;;;:17;:33;;;;;:66;;43063:29;;43026:33;;:66;;43063:29;;43026:66;:::i;:::-;;;;-1:-1:-1;;42922:182:0;43172:10;43146:37;;;;:25;:37;;;;;;;:53;;;;:37;:53;;;;;;;;43284:17;:29;;;;;;43248:32;;;:17;:32;;;;;:65;;43284:29;;43248:32;;:65;;43284:29;;43248:65;:::i;:::-;;;;-1:-1:-1;;;;42521:800:0:o;55972:207::-;31469:5;;56080:20;;31469:5;;31455:10;:19;;:74;;;31478:51;31496:10;31508:20;31478:17;:51::i;:::-;31447:107;;;;;;;13125:2:1;31447:107:0;;;13107:21:1;13164:2;13144:18;;;13137:30;13203:22;13183:18;;;13176:50;13243:18;;31447:107:0;12923:344:1;31447:107:0;-1:-1:-1;56113:36:0::1;::::0;;::::1;;::::0;;;:14:::1;:36;::::0;;;;:58;;;::::1;::::0;;;::::1;;::::0;;55972:207::o;52922:97::-;31266:5;;;;31252:10;:19;;:79;;-1:-1:-1;31289:42:0;31275:10;:56;31252:79;31244:113;;;;;;;13829:2:1;31244:113:0;;;13811:21:1;13868:2;13848:18;;;13841:30;13907:23;13887:18;;;13880:51;13948:18;;31244:113:0;13627:345:1;31244:113:0;52997:14:::1;::::0;;52979:32;;::::1;52997:14;::::0;;::::1;52996:15;52979:32;::::0;;52922:97::o;84916:259::-;85016:7;21632:1;22238:7;;:19;22230:63;;;;;;;10744:2:1;22230:63:0;;;10726:21:1;10783:2;10763:18;;;10756:30;10822:33;10802:18;;;10795:61;10873:18;;22230:63:0;10542:355:1;22230:63:0;21632:1;22371:18;;85044:17:::1;::::0;::::1;::::0;::::1;;;:26;85036:57;;;::::0;::::1;::::0;;17287:2:1;85036:57:0::1;::::0;::::1;17269:21:1::0;17326:2;17306:18;;;17299:30;17365:20;17345:18;;;17338:48;17403:18;;85036:57:0::1;17085:342:1::0;85036:57:0::1;85111:56;85127:10;85139:19;85160:6;85111:15;:56::i;41796:610::-:0;41895:10;41875:31;;;;:19;:31;;;;;;;;41867:57;;;;;;;16587:2:1;41867:57:0;;;16569:21:1;16626:2;16606:18;;;16599:30;16665:15;16645:18;;;16638:43;16698:18;;41867:57:0;16385:337:1;41867:57:0;42010:10;41988:33;;;;:21;:33;;;;;;;;;:49;;;;;;;;;;;;;;;;41987:50;41935:102;;;;;;;42140:41;;;;;;;;:55;42136:263;;42211:41;;;42263:1;42211:41;;;:25;:41;;;;;;;:54;;;;;;42354:17;:33;;;;;;42339:10;42321:29;;:17;:29;;;;;:66;;42354:33;;42321:29;;:66;;42354:33;;42321:66;:::i;:::-;;;;-1:-1:-1;;42136:263:0;41796:610;:::o;33913:452::-;33974:16;34003:32;34038:16;34055:9;34038:27;;;;;;;;:::i;:::-;;;;;;;;;;;;;;-1:-1:-1;34080:38:0;;34076:282;;34261:4;34219:27;34247:9;34219:38;;;;;;;;:::i;:::-;;;;;;;;;34168:24;34147:67;;;:69;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:110;;;;:::i;:::-;34146:119;;;;:::i;:::-;34135:130;;34076:282;;;34318:17;34336:9;34318:28;;;;;;;;:::i;:::-;;;;;;;;;34307:39;;33992:373;33913:452;;;:::o;51208:761::-;51325:9;51320:642;51344:16;:23;51340:27;;51320:642;;;51389:32;51424:16;51441:1;51424:19;;;;;;;;:::i;:::-;;;;;;;;;;;;;;-1:-1:-1;51462:38:0;;51458:493;;51525:12;:61;;;;51560:22;51583:1;51560:25;;;;;;;;:::i;:::-;;;;;;;;;51542:15;:43;51525:61;51521:415;;;51700:106;;;;;51783:4;51700:106;;;17606:74:1;51790:15:0;17696:18:1;;;17689:34;51700:74:0;;;;;;17579:18:1;;51700:106:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;51667:27;51695:1;51667:30;;;;;;;;:::i;:::-;;;;;;;;:139;;;;51878:24;51857:57;;;:59;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;51829:22;51852:1;51829:25;;;;;;;;:::i;:::-;;;;;;;;;;:87;51521:415;-1:-1:-1;51369:3:0;;;;:::i;:::-;;;;51320:642;;54379:958;31266:5;;;;31252:10;:19;;:79;;-1:-1:-1;31289:42:0;31275:10;:56;31252:79;31244:113;;;;;;;13829:2:1;31244:113:0;;;13811:21:1;13868:2;13848:18;;;13841:30;13907:23;13887:18;;;13880:51;13948:18;;31244:113:0;13627:345:1;31244:113:0;54788:13;;28117:4:::1;-1:-1:-1::0;54788:37:0::1;54780:69;;;::::0;::::1;::::0;;17936:2:1;54780:69:0::1;::::0;::::1;17918:21:1::0;17975:2;17955:18;;;17948:30;18014:21;17994:18;;;17987:49;18053:18;;54780:69:0::1;17734:343:1::0;54780:69:0::1;54973:13:::0;;::::1;::::0;54990:1:::1;-1:-1:-1::0;54973:18:0;::::1;::::0;54972:44:::1;;-1:-1:-1::0;54997:13:0;;::::1;::::0;55014:1:::1;-1:-1:-1::0;54997:18:0::1;54972:44;54964:69;;;::::0;::::1;::::0;;18625:2:1;54964:69:0::1;::::0;::::1;18607:21:1::0;18664:2;18644:18;;;18637:30;18703:14;18683:18;;;18676:42;18735:18;;54964:69:0::1;18423:336:1::0;54964:69:0::1;55068:13:::0;;55046:19:::1;:35:::0;55068:13:::1;55115::::0;::::1;::::0;55092:20:::1;:36:::0;55170:13;;::::1;::::0;55139:28:::1;:44:::0;55221:13;;::::1;::::0;55194:24:::1;:40:::0;55276:13;;::::1;::::0;55245:28:::1;:44:::0;55316:13;::::1;::::0;55300::::1;:29:::0;54379:958::o;51977:363::-;52060:25;52079:5;52060:18;:25::i;:::-;52155:16;:14;:16::i;:::-;52137:15;:34;52207:12;;52188:15;:31;52184:149;;52236:14;:12;:14::i;:::-;51977:363::o;52184:149::-;52292:29;:27;:29::i;523:106::-;581:7;612:1;608;:5;:13;;620:1;608:13;;;616:1;608:13;601:20;523:106;-1:-1:-1;;;523:106:0:o;83039:1705::-;83285:7;83254:14;83270:4;31660:41;31683:7;31692:8;31660:22;:41::i;:::-;83313:13:::1;::::0;;;::::1;;;:22;83305:49;;;::::0;::::1;::::0;;18966:2:1;83305:49:0::1;::::0;::::1;18948:21:1::0;19005:2;18985:18;;;18978:30;19044:16;19024:18;;;19017:44;19078:18;;83305:49:0::1;18764:338:1::0;83305:49:0::1;83381:13;;83373:4;:21;;83365:60;;;::::0;::::1;::::0;;15480:2:1;83365:60:0::1;::::0;::::1;15462:21:1::0;15519:2;15499:18;;;15492:30;15558:28;15538:18;;;15531:56;15604:18;;83365:60:0::1;15278:350:1::0;83365:60:0::1;83452:28;;83444:4;:36;;83436:75;;;::::0;::::1;::::0;;15835:2:1;83436:75:0::1;::::0;::::1;15817:21:1::0;15874:2;15854:18;;;15847:30;15913:29;15893:18;;;15886:57;15960:18;;83436:75:0::1;15633:351:1::0;83436:75:0::1;83594:96;83634:12;83649:14;83673:4;83680:9;83594:31;:96::i;:::-;83750:23;83776:20;83791:4;83776:14;:20::i;:::-;83895:33;::::0;::::1;83807:14;83895:33:::0;;;:17:::1;:33;::::0;;;;;;;;83834:95;;19353:66:1;19340:2;19336:15;;;19332:88;83834:95:0;;::::1;19320:101:1::0;;;;19437:12;;;19430:28;;;19474:12;;;19467:28;;;19511:12;;;19504:28;83750:46:0;;-1:-1:-1;83807:14:0;19548:13:1;;83834:95:0::1;::::0;;;;;::::1;::::0;;;;;;83824:106;;83834:95:::1;83824:106:::0;;::::1;::::0;83987:28:::1;::::0;::::1;;::::0;;;:12:::1;:28:::0;;;;;84021:164:::1;::::0;::::1;::::0;;;;;;;::::1;::::0;;;;;;;;;83824:106;;-1:-1:-1;83987:28:0;84021:164;;;84122:22:::1;84140:4:::0;84068:15;84122:22:::1;:::i;:::-;84021:164:::0;;::::1;::::0;;::::1;::::0;;;83987:199;;::::1;::::0;;::::1;::::0;;-1:-1:-1;83987: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;84230:23:::1;:36:::0;;84257:9;;-1:-1:-1;84230:36:0::1;::::0;84257:9;;84230:36:::1;:::i;:::-;::::0;;;-1:-1:-1;;84277:33:0::1;::::0;::::1;;::::0;;;:17:::1;:33;::::0;;;;:46;;84314:9;;84277:33;:46:::1;::::0;84314:9;;84277:46:::1;:::i;:::-;::::0;;;-1:-1:-1;84349:17:0::1;::::0;-1:-1:-1;84369:27:0::1;84381:14:::0;84369:11:::1;:27::i;:::-;84349:47:::0;-1:-1:-1;84415:23:0::1;::::0;::::1;::::0;84411:70:::1;;84440:28;::::0;::::1;;::::0;;;:17:::1;:28;::::0;;;;:41;;84472:9;;84440:28;:41:::1;::::0;84472:9;;84440:41:::1;:::i;:::-;::::0;;;-1:-1:-1;;84411:70:0::1;84334:159;84579:45;84602:14;84618:5;84579:22;:45::i;:::-;84642:68;::::0;;19803:25:1;;;19859:2;19844:18;;19837:34;;;19887:18;;;19880:34;;;84642:68:0::1;19950:55:1::0;;;19945:2;19930:18;;19923:83;84642:68:0;::::1;::::0;::::1;::::0;19790:3:1;19775:19;84642:68:0::1;;;;;;;84730:6:::0;83039:1705;-1:-1:-1;;;;;;;;;83039:1705:0:o;45017:585::-;45079:21;;;;45075:520;;45156:27;45186:15;45193:7;45186:6;:15::i;:::-;45156:45;;45264:9;45259:118;45283:10;:17;45279:1;:21;45259:118;;;45348:10;45359:1;45348:13;;;;;;;;:::i;:::-;;;;;;;;;;;;45326:16;;;;;;;:7;:16;;;;;;:19;;;;;;;;;;:35;45343:1;45302:3;45343:1;45302:3;:::i;:::-;;;;45259:118;;;;45444:9;45439:145;45463:10;:17;45459:1;:21;45439:145;;;45544:21;45566:1;45544:24;;;;;;;;:::i;:::-;;;;;;;;;;;;;45506:32;;;;;:23;:32;;;;;;:35;;;;;;;;:62;45539:1;45482:3;45539:1;45482:3;:::i;:::-;;;;45439:145;;33772:133;33831:7;33858:39;33867:15;33884:12;;33858:8;:39::i;:::-;33851:46;;33772:133;:::o;46662:1194::-;46810:31;46785:8;46795:4;31660:41;31683:7;31692:8;31660:22;:41::i;:::-;46940:29:::1;::::0;::::1;;::::0;;;:19:::1;:29;::::0;;;;46972:15:::1;46940:47:::0;;47070:23:::1;::::0;;;::::1;;;:32;47062:70;;;::::0;::::1;::::0;;11293:2:1;47062:70:0::1;::::0;::::1;11275:21:1::0;11332:2;11312:18;;;11305:30;11371:27;11351:18;;;11344:55;11416:18;;47062:70:0::1;11091:349:1::0;47062:70:0::1;47244:12;:19:::0;47230:34:::1;::::0;::::1;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;-1:-1:-1;47230:34:0::1;;47213:51;;47282:9;47277:419;47301:12;:19:::0;47297:23;::::1;47277:419;;;47362:17;::::0;::::1;;::::0;;;:7:::1;:17;::::0;;;;;;;:20;;;;;;;;;47342:17;;:14;;47380:1;;47342:17;::::1;;;;;:::i;:::-;;::::0;;::::1;::::0;;;;;;:40;;;;47397:17:::1;::::0;::::1;47420:1;47397:17:::0;;;:7:::1;:17:::0;;;;;;:20;;;;;;;;;:24;;;47440:17;;:14;;47415:1;;47440:17;::::1;;;;;:::i;:::-;;;;;;;:21;47436:249;;;47482:84;47510:12;47523:1;47510:15;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;47527:19;47548:14;47563:1;47548:17;;;;;;;;:::i;:::-;;;;;;;47482:27;:84::i;:::-;47603:8;47592:77;;;47613:14;47628:1;47613:17;;;;;;;;:::i;:::-;;;;;;;47632:12;47645:1;47632:15;;;;;;;;:::i;:::-;;::::0;;;::::1;::::0;;;;::::1;::::0;47592:77:::1;::::0;;20219:25:1;;;47632:15:0::1;::::0;;::::1;20321:18:1::0;;;20314:43;;;;20393:15;;20373:18;;;20366:43;20207:2;20192:18;47592:77:0::1;;;;;;;47436:249;47322:3:::0;::::1;::::0;::::1;:::i;:::-;;;;47277:419;;;;46662:1194:::0;;;;;;;:::o;18949:361::-;19144:45;;;19133:10;17624:55:1;;;19144:45:0;;;17606:74:1;17696:18;;;;17689:34;;;19144:45:0;;;;;;;;;;17579:18:1;;;;19144:45:0;;;;;;;;;;;;;19133:57;;-1:-1:-1;;;;19133:10:0;;;;:57;;19144:45;19133:57;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;19097:93;;;;19209:7;:57;;;;-1:-1:-1;19221:11:0;;:16;;:44;;;19252:4;19241:24;;;;;;;;;;;;:::i;:::-;19201:101;;;;;;;21414:2:1;19201:101:0;;;21396:21:1;21453:2;21433:18;;;21426:30;21492:33;21472:18;;;21465:61;21543:18;;19201:101:0;21212:355:1;79211:508:0;79293:31;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;79293:31:0;79326:15;;79354:280;79378:28;;;;;;;:12;:28;;;;;:35;79374:39;;79354:280;;;79449:28;;;;;;;:12;:28;;;;;:31;;79478:1;;79449:31;;;;;;:::i;:::-;;;;;;;;;;;:38;;;79439:6;:48;79435:188;;79522:28;;;;;;;:12;:28;;;;;:31;;79551:1;;79522:31;;;;;;:::i;:::-;;;;;;;;;;;79507:46;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;79582:1;79572:11;;79602:5;;79435:188;79415:3;;;;:::i;:::-;;;;79354:280;;;-1:-1:-1;79652:19:0;;:29;;79644:57;;;;;;;21774:2:1;79644:57:0;;;21756:21:1;21813:2;21793:18;;;21786:30;21852:17;21832:18;;;21825:45;21887:18;;79644:57:0;21572:339:1;79644:57:0;79211:508;;;;;:::o;19318:402::-;19543:51;;;19532:10;22197:15:1;;;19543:51:0;;;22179:34:1;22249:15;;;22229:18;;;22222:43;22281:18;;;;22274:34;;;19543:51:0;;;;;;;;;;22091:18:1;;;;19543:51:0;;;;;;;;;;;;;19532:63;;-1:-1:-1;;;;19532:10:0;;;;:63;;19543:51;19532:63;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;19496:99;;;;19614:7;:57;;;;-1:-1:-1;19626:11:0;;:16;;:44;;;19657:4;19646:24;;;;;;;;;;;;:::i;:::-;19606:106;;;;;;;22521:2:1;19606:106:0;;;22503:21:1;22560:2;22540:18;;;22533:30;22599:34;22579:18;;;22572:62;22670:6;22650:18;;;22643:34;22694:19;;19606:106:0;22319:400:1;19606:106:0;19406:314;;19318:402;;;;:::o;85310:1555::-;85456:7;85539:53;85550:14;85566:19;85587:4;85539:10;:53::i;:::-;;85646:28;85676:21;85701:33;85711:14;85727:6;85701:9;:33::i;:::-;85645:89;;;;85772:9;:26;;;85753:15;:45;;:71;;;-1:-1:-1;85802:14:0;;;;:22;;:14;:22;85753:71;85745:106;;;;;;;22926:2:1;85745:106:0;;;22908:21:1;22965:2;22945:18;;;22938:30;23004:24;22984:18;;;22977:52;23046:18;;85745:106:0;22724:346:1;85745:106:0;85882:19;;;;85918:13;;85914:915;;86062:82;86098:12;86113:19;86134:9;86062:27;:82::i;:::-;86223:9;86196:23;;:36;;;;;;;:::i;:::-;;;;-1:-1:-1;;86247:33:0;;;;;;;:17;:33;;;;;:46;;86284:9;;86247:33;:46;;86284:9;;86247:46;:::i;:::-;;;;-1:-1:-1;86327:17:0;;-1:-1:-1;86347:27:0;86359:14;86347:11;:27::i;:::-;86327:47;-1:-1:-1;86397:23:0;;;;86393:70;;86422:28;;;;;;;:17;:28;;;;;:41;;86454:9;;86422:28;:41;;86454:9;;86422:41;:::i;:::-;;;;-1:-1:-1;;86393:70:0;-1:-1:-1;86550:28:0;;;;;;;:12;:28;;;;;:43;;86579:13;;86550:43;;;;;;:::i;:::-;;;;;;;;;;;;;86543:50;;;;;;;;;;;;;;;;;;;;;;;;;;86680:45;;86703:14;;86680:22;:45::i;:::-;86747:70;;;23277:25:1;;;23333:2;23318:18;;23311:34;;;86747:70:0;23381:55:1;;;23361:18;;;23354:83;86747:70:0;;;;;;;;;;;23265:2:1;86747:70:0;;;85914:915;86848:9;85310:1555;-1:-1:-1;;;;;;85310:1555:0:o;47943:2814::-;48064:9;48059:327;48083:18;:25;48079:29;;48059:327;;;48130:34;48167:18;48186:1;48167:21;;;;;;;;:::i;:::-;;;;;;;;;;;;;;-1:-1:-1;48207:40:0;;48203:172;;48268:91;;;;;48353:4;48268:91;;;4150:74:1;48268:76:0;;;;;;4123:18:1;;48268:91:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;48203:172;-1:-1:-1;48110:3:0;;;;:::i;:::-;;;;48059:327;;;;48746:27;29633:6;48802:12;;48784:15;:30;;;;:::i;:::-;48776:57;;;;:::i;:::-;48746:87;;48972:9;48967:284;48991:12;:19;48987:23;;48967:284;;;49113:12;49126:1;49113:15;;;;;;;;:::i;:::-;;;;;;;;;;;49106:48;;;;;49148:4;49106:48;;;4150:74:1;49113:15:0;;;;;49106:33;;4123:18:1;;49106:48:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;49077:23;:19;49099:1;49077:23;:::i;:::-;29633:6;49041:14;49053:1;49041:11;:14::i;:::-;:32;;;;:::i;:::-;:60;;;;:::i;:::-;49040:114;;49220:12;49233:1;49220:15;;;;;;;;:::i;:::-;;;;;;;;;;;;49163:73;;;23940:34:1;49163:73:0;;;23928:47:1;;;;24005:6;23991:12;;;23984:28;24050:2;24046:15;;;24028:12;;;24021:110;24147:12;;49163:73:0;;;;;;;;;;;;49032:207;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;49012:3:0;;;;:::i;:::-;;;;48967:284;;;-1:-1:-1;29633:6:0;49463:23;:19;49485:1;49463:23;:::i;:::-;49462:43;;;;:::i;:::-;49446:12;;:60;;;;:::i;:::-;49431:12;:75;49559:29;:27;:29::i;:::-;49658:16;:14;:16::i;:::-;49640:15;:34;-1:-1:-1;47943:2814:0:o;50765:435::-;50852:34;50889:17;:15;:17::i;:::-;50852:54;;50969:9;50964:133;50988:21;:28;50984:32;;50964:133;;;51065:17;51083:1;51065:20;;;;;;;;:::i;:::-;;;;;;;51038:21;51060:1;51038:24;;;;;;;;:::i;:::-;;;;;;;;;;:47;51018:3;;;;:::i;:::-;;;;50964:133;;;;51166:26;:24;:26::i;:::-;51149:14;:43;-1:-1:-1;50765:435:0:o;14:196:1:-;82:20;;142:42;131:54;;121:65;;111:93;;200:1;197;190:12;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;2531:1011::-;2760:2;2812:21;;;2882:13;;2785:18;;;2904:22;;;2731:4;;2760:2;2945;;2963:18;;;;3004:15;;;2731:4;3047:469;3061:6;3058:1;3055:13;3047:469;;;3120:13;;3158:9;;3146:22;;3208:11;;;3202:18;3188:12;;;3181:40;3261:11;;;3255:18;3241:12;;;3234:40;3297:4;3341:11;;;3335:18;3321:12;;;3314:40;3377:4;3421:11;;;3415:18;3401:12;;;3394:40;3463:4;3454:14;;;;3491:15;;;;3083:1;3076:9;3047:469;;;-1:-1:-1;3533:3:1;;2531:1011;-1:-1:-1;;;;;;;2531:1011:1:o;3547:260::-;3615:6;3623;3676:2;3664:9;3655:7;3651:23;3647:32;3644:52;;;3692:1;3689;3682:12;3644:52;3715:29;3734:9;3715:29;:::i;:::-;3705:39;;3763:38;3797:2;3786:9;3782:18;3763:38;:::i;:::-;3753:48;;3547:260;;;;;:::o;4235:118::-;4321:5;4314:13;4307:21;4300:5;4297:32;4287:60;;4343:1;4340;4333:12;4358:315;4423:6;4431;4484:2;4472:9;4463:7;4459:23;4455:32;4452:52;;;4500:1;4497;4490:12;4452:52;4523:29;4542:9;4523:29;:::i;:::-;4513:39;;4602:2;4591:9;4587:18;4574:32;4615:28;4637:5;4615:28;:::i;:::-;4662:5;4652:15;;;4358:315;;;;;:::o;4931:254::-;4999:6;5007;5060:2;5048:9;5039:7;5035:23;5031:32;5028:52;;;5076:1;5073;5066:12;5028:52;5099:29;5118:9;5099:29;:::i;:::-;5089:39;5175:2;5160:18;;;;5147:32;;-1:-1:-1;;;4931:254:1:o;6235:511::-;6303:6;6311;6319;6372:2;6360:9;6351:7;6347:23;6343:32;6340:52;;;6388:1;6385;6378:12;6340:52;6427:9;6414:23;6446:28;6468:5;6446:28;:::i;:::-;6493:5;-1:-1:-1;6550:2:1;6535:18;;6522:32;6563:30;6522:32;6563:30;:::i;:::-;6612:7;-1:-1:-1;6671:2:1;6656:18;;6643:32;6684:30;6643:32;6684:30;:::i;:::-;6733:7;6723:17;;;6235:511;;;;;:::o;6751:403::-;6837:6;6845;6853;6861;6914:3;6902:9;6893:7;6889:23;6885:33;6882:53;;;6931:1;6928;6921:12;6882:53;6954:29;6973:9;6954:29;:::i;:::-;6944:39;;7030:2;7019:9;7015:18;7002:32;6992:42;;7053:38;7087:2;7076:9;7072:18;7053:38;:::i;:::-;7043:48;;7110:38;7144:2;7133:9;7129:18;7110:38;:::i;:::-;7100:48;;6751:403;;;;;;;:::o;7159:254::-;7227:6;7235;7288:2;7276:9;7267:7;7263:23;7259:32;7256:52;;;7304:1;7301;7294:12;7256:52;7340:9;7327:23;7317:33;;7369:38;7403:2;7392:9;7388:18;7369:38;:::i;7418:241::-;7474:6;7527:2;7515:9;7506:7;7502:23;7498:32;7495:52;;;7543:1;7540;7533:12;7495:52;7582:9;7569:23;7601:28;7623:5;7601:28;:::i;7664:184::-;7716:77;7713:1;7706:88;7813:4;7810:1;7803:15;7837:4;7834:1;7827:15;7853:915;7935:6;7988:3;7976:9;7967:7;7963:23;7959:33;7956:53;;;8005:1;8002;7995:12;7956:53;8054:7;8047:4;8036:9;8032:20;8028:34;8018:62;;8076:1;8073;8066:12;8018:62;8109:2;8103:9;8151:3;8143:6;8139:16;8221:6;8209:10;8206:22;8185:18;8173:10;8170:34;8167:62;8164:242;;;8262:77;8259:1;8252:88;8363:4;8360:1;8353:15;8391:4;8388:1;8381:15;8164:242;8422:2;8415:22;8457:6;8501:3;8486:19;;8517;;;8514:39;;;8549:1;8546;8539:12;8514:39;8573:9;8591:146;8607:6;8602:3;8599:15;8591:146;;;8675:17;;8663:30;;8722:4;8713:14;;;;8624;8591:146;;;-1:-1:-1;8756:6:1;;7853:915;-1:-1:-1;;;;;7853:915:1:o;8773:184::-;8825:77;8822:1;8815:88;8922:4;8919:1;8912:15;8946:4;8943:1;8936:15;8962:184;9014:77;9011:1;9004:88;9111:4;9108:1;9101:15;9135:4;9132:1;9125:15;9151:125;9191:4;9219:1;9216;9213:8;9210:34;;;9224:18;;:::i;:::-;-1:-1:-1;9261:9:1;;9151:125::o;9281:228::-;9321:7;9447:1;9379:66;9375:74;9372:1;9369:81;9364:1;9357:9;9350:17;9346:105;9343:131;;;9454:18;;:::i;:::-;-1:-1:-1;9494:9:1;;9281:228::o;9514:274::-;9554:1;9580;9570:189;;9615:77;9612:1;9605:88;9716:4;9713:1;9706:15;9744:4;9741:1;9734:15;9570:189;-1:-1:-1;9773:9:1;;9514:274::o;9793:128::-;9833:3;9864:1;9860:6;9857:1;9854:13;9851:39;;;9870:18;;:::i;:::-;-1:-1:-1;9906:9:1;;9793:128::o;9926:195::-;9965:3;9996:66;9989:5;9986:77;9983:103;;10066:18;;:::i;:::-;-1:-1:-1;10113:1:1;10102:13;;9926:195::o;10902:184::-;10972:6;11025:2;11013:9;11004:7;11000:23;10996:32;10993:52;;;11041:1;11038;11031:12;10993:52;-1:-1:-1;11064:16:1;;10902:184;-1:-1:-1;10902:184:1:o;11445:188::-;11524:13;;11577:30;11566:42;;11556:53;;11546:81;;11623:1;11620;11613:12;11638:526;11744:6;11752;11760;11768;11776;11829:3;11817:9;11808:7;11804:23;11800:33;11797:53;;;11846:1;11843;11836:12;11797:53;11869:40;11899:9;11869:40;:::i;:::-;11859:50;;11928:49;11973:2;11962:9;11958:18;11928:49;:::i;:::-;11918:59;;12017:2;12006:9;12002:18;11996:25;11986:35;;12040:49;12085:2;12074:9;12070:18;12040:49;:::i;:::-;12030:59;;12108:50;12153:3;12142:9;12138:19;12108:50;:::i;:::-;12098:60;;11638:526;;;;;;;;:::o;20420:258::-;20492:1;20502:113;20516:6;20513:1;20510:13;20502:113;;;20592:11;;;20586:18;20573:11;;;20566:39;20538:2;20531:10;20502:113;;;20633:6;20630:1;20627:13;20624:48;;;-1:-1:-1;;20668:1:1;20650:16;;20643:27;20420:258::o;20683:274::-;20812:3;20850:6;20844:13;20866:53;20912:6;20907:3;20900:4;20892:6;20888:17;20866:53;:::i;:::-;20935:16;;;;;20683:274;-1:-1:-1;;20683:274:1:o;20962:245::-;21029:6;21082:2;21070:9;21061:7;21057:23;21053:32;21050:52;;;21098:1;21095;21088:12;21050:52;21130:9;21124:16;21149:28;21171:5;21149:28;:::i;23448:245::-;23527:6;23535;23588:2;23576:9;23567:7;23563:23;23559:32;23556:52;;;23604:1;23601;23594:12;23556:52;-1:-1:-1;;23627:16:1;;23683:2;23668:18;;;23662:25;23627:16;;23662:25;;-1:-1:-1;23448:245:1:o;24170:442::-;24319:2;24308:9;24301:21;24282:4;24351:6;24345:13;24394:6;24389:2;24378:9;24374:18;24367:34;24410:66;24469:6;24464:2;24453:9;24449:18;24444:2;24436:6;24432:15;24410:66;:::i;:::-;24528:2;24516:15;24533:66;24512:88;24497:104;;;;24603:2;24493:113;;24170:442;-1:-1:-1;;24170:442:1:o
Swarm Source
ipfs://d1bcf14daa5da273eb104d6a8414d0641f8933549ff1680562afa0fd13d70846
Loading...
Loading
Loading...
Loading
Net Worth in USD
$5,825.46
Net Worth in ETH
2.993007
Token Allocations
FXS
100.00%
Multichain Portfolio | 34 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|---|---|---|---|---|
| ETH | 100.00% | $0.64278 | 9,062.9206 | $5,825.46 |
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.