Contract
0xd1df24e8d225b20f9c8f4912be88cccec93f36e5
12
Contract Overview
My Name Tag:
Not Available
[ Download CSV Export ]
Latest 25 internal transaction
[ Download CSV Export ]
Contract Name:
FraxCCFarmV3_ArbiSaddleL2D4
Compiler Version
v0.8.17+commit.8df45f5f
Contract Source Code (Solidity)
/** *Submitted for verification at Arbiscan.io on 2023-02-03 */ // SPDX-License-Identifier: GPL-2.0-or-later pragma solidity >=0.8.0; // Sources flattened with hardhat v2.12.5 https://hardhat.org // File contracts/Common/Context.sol /* * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with GSN meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract Context { function _msgSender() internal view virtual returns (address payable) { return payable(msg.sender); } function _msgData() internal view virtual returns (bytes memory) { this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691 return msg.data; } } // File contracts/Math/SafeMath.sol /** * @dev Wrappers over Solidity's arithmetic operations with added overflow * checks. * * Arithmetic operations in Solidity wrap on overflow. This can easily result * in bugs, because programmers usually assume that an overflow raises an * error, which is the standard behavior in high level programming languages. * `SafeMath` restores this intuition by reverting the transaction when an * operation overflows. * * Using this library instead of the unchecked operations eliminates an entire * class of bugs, so it's recommended to use it always. */ library SafeMath { /** * @dev Returns the addition of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `+` operator. * * Requirements: * - Addition cannot overflow. */ function add(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c = a + b; require(c >= a, "SafeMath: addition overflow"); return c; } /** * @dev Returns the subtraction of two unsigned integers, reverting on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b) internal pure returns (uint256) { return sub(a, b, "SafeMath: subtraction overflow"); } /** * @dev Returns the subtraction of two unsigned integers, reverting with custom message on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * - Subtraction cannot overflow. * * _Available since v2.4.0._ */ function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b <= a, errorMessage); uint256 c = a - b; return c; } /** * @dev Returns the multiplication of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `*` operator. * * Requirements: * - Multiplication cannot overflow. */ function mul(uint256 a, uint256 b) internal pure returns (uint256) { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 if (a == 0) { return 0; } uint256 c = a * b; require(c / a == b, "SafeMath: multiplication overflow"); return c; } /** * @dev Returns the integer division of two unsigned integers. Reverts on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * - The divisor cannot be zero. */ function div(uint256 a, uint256 b) internal pure returns (uint256) { return div(a, b, "SafeMath: division by zero"); } /** * @dev Returns the integer division of two unsigned integers. Reverts with custom message on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * - The divisor cannot be zero. * * _Available since v2.4.0._ */ function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { // Solidity only automatically asserts when dividing by 0 require(b > 0, errorMessage); uint256 c = a / b; // assert(a == b * c + a % b); // There is no case in which this doesn't hold return c; } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * Reverts when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b) internal pure returns (uint256) { return mod(a, b, "SafeMath: modulo by zero"); } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * Reverts with custom message when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * - The divisor cannot be zero. * * _Available since v2.4.0._ */ function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b != 0, errorMessage); return a % b; } } // File contracts/ERC20/IERC20.sol /** * @dev Interface of the ERC20 standard as defined in the EIP. Does not include * the optional functions; to access them see {ERC20Detailed}. */ interface IERC20 { /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `recipient`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address recipient, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `sender` to `recipient` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); } // File contracts/Utils/Address.sol /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize, which returns 0 for contracts in // construction, since the code is only stored at the end of the // constructor execution. uint256 size; // solhint-disable-next-line no-inline-assembly assembly { size := extcodesize(account) } return size > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); // solhint-disable-next-line avoid-low-level-calls, avoid-call-value (bool success, ) = recipient.call{ value: amount }(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain`call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCall(target, data, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); require(isContract(target), "Address: call to non-contract"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = target.call{ value: value }(data); return _verifyCallResult(success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data, string memory errorMessage) internal view returns (bytes memory) { require(isContract(target), "Address: static call to non-contract"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = target.staticcall(data); return _verifyCallResult(success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { return functionDelegateCall(target, data, "Address: low-level delegate call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) { require(isContract(target), "Address: delegate call to non-contract"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = target.delegatecall(data); return _verifyCallResult(success, returndata, errorMessage); } function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) { if (success) { return returndata; } else { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly // solhint-disable-next-line no-inline-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } } } // File contracts/ERC20/ERC20.sol /** * @dev Implementation of the {IERC20} interface. * * This implementation is agnostic to the way tokens are created. This means * that a supply mechanism has to be added in a derived contract using {_mint}. * For a generic mechanism see {ERC20Mintable}. * * TIP: For a detailed writeup see our guide * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How * to implement supply mechanisms]. * * We have followed general OpenZeppelin guidelines: functions revert instead * of returning `false` on failure. This behavior is nonetheless conventional * and does not conflict with the expectations of ERC20 applications. * * Additionally, an {Approval} event is emitted on calls to {transferFrom}. * This allows applications to reconstruct the allowance for all accounts just * by listening to said events. Other implementations of the EIP may not emit * these events, as it isn't required by the specification. * * Finally, the non-standard {decreaseAllowance} and {increaseAllowance} * functions have been added to mitigate the well-known issues around setting * allowances. See {IERC20-approve}. */ contract ERC20 is Context, IERC20 { using SafeMath for uint256; mapping (address => uint256) private _balances; mapping (address => mapping (address => uint256)) private _allowances; uint256 private _totalSupply; string private _name; string private _symbol; uint8 private _decimals; /** * @dev Sets the values for {name} and {symbol}, initializes {decimals} with * a default value of 18. * * To select a different value for {decimals}, use {_setupDecimals}. * * All three of these values are immutable: they can only be set once during * construction. */ constructor (string memory __name, string memory __symbol) public { _name = __name; _symbol = __symbol; _decimals = 18; } /** * @dev Returns the name of the token. */ function name() public view returns (string memory) { return _name; } /** * @dev Returns the symbol of the token, usually a shorter version of the * name. */ function symbol() public view returns (string memory) { return _symbol; } /** * @dev Returns the number of decimals used to get its user representation. * For example, if `decimals` equals `2`, a balance of `505` tokens should * be displayed to a user as `5,05` (`505 / 10 ** 2`). * * Tokens usually opt for a value of 18, imitating the relationship between * Ether and Wei. This is the value {ERC20} uses, unless {_setupDecimals} is * called. * * NOTE: This information is only used for _display_ purposes: it in * no way affects any of the arithmetic of the contract, including * {IERC20-balanceOf} and {IERC20-transfer}. */ function decimals() public view returns (uint8) { return _decimals; } /** * @dev See {IERC20-totalSupply}. */ function totalSupply() public view override returns (uint256) { return _totalSupply; } /** * @dev See {IERC20-balanceOf}. */ function balanceOf(address account) public view override returns (uint256) { return _balances[account]; } /** * @dev See {IERC20-transfer}. * * Requirements: * * - `recipient` cannot be the zero address. * - the caller must have a balance of at least `amount`. */ function transfer(address recipient, uint256 amount) public virtual override returns (bool) { _transfer(_msgSender(), recipient, amount); return true; } /** * @dev See {IERC20-allowance}. */ function allowance(address owner, address spender) public view virtual override returns (uint256) { return _allowances[owner][spender]; } /** * @dev See {IERC20-approve}. * * Requirements: * * - `spender` cannot be the zero address.approve(address spender, uint256 amount) */ function approve(address spender, uint256 amount) public virtual override returns (bool) { _approve(_msgSender(), spender, amount); return true; } /** * @dev See {IERC20-transferFrom}. * * Emits an {Approval} event indicating the updated allowance. This is not * required by the EIP. See the note at the beginning of {ERC20}; * * Requirements: * - `sender` and `recipient` cannot be the zero address. * - `sender` must have a balance of at least `amount`. * - the caller must have allowance for `sender`'s tokens of at least * `amount`. */ function transferFrom(address sender, address recipient, uint256 amount) public virtual override returns (bool) { _transfer(sender, recipient, amount); _approve(sender, _msgSender(), _allowances[sender][_msgSender()].sub(amount, "ERC20: transfer amount exceeds allowance")); return true; } /** * @dev Atomically increases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. */ function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) { _approve(_msgSender(), spender, _allowances[_msgSender()][spender].add(addedValue)); return true; } /** * @dev Atomically decreases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. * - `spender` must have allowance for the caller of at least * `subtractedValue`. */ function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) { _approve(_msgSender(), spender, _allowances[_msgSender()][spender].sub(subtractedValue, "ERC20: decreased allowance below zero")); return true; } /** * @dev Moves tokens `amount` from `sender` to `recipient`. * * This is internal function is equivalent to {transfer}, and can be used to * e.g. implement automatic token fees, slashing mechanisms, etc. * * Emits a {Transfer} event. * * Requirements: * * - `sender` cannot be the zero address. * - `recipient` cannot be the zero address. * - `sender` must have a balance of at least `amount`. */ function _transfer(address sender, address recipient, uint256 amount) internal virtual { require(sender != address(0), "ERC20: transfer from the zero address"); require(recipient != address(0), "ERC20: transfer to the zero address"); _beforeTokenTransfer(sender, recipient, amount); _balances[sender] = _balances[sender].sub(amount, "ERC20: transfer amount exceeds balance"); _balances[recipient] = _balances[recipient].add(amount); emit Transfer(sender, recipient, amount); } /** @dev Creates `amount` tokens and assigns them to `account`, increasing * the total supply. * * Emits a {Transfer} event with `from` set to the zero address. * * Requirements * * - `to` cannot be the zero address. */ function _mint(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: mint to the zero address"); _beforeTokenTransfer(address(0), account, amount); _totalSupply = _totalSupply.add(amount); _balances[account] = _balances[account].add(amount); emit Transfer(address(0), account, amount); } /** * @dev Destroys `amount` tokens from the caller. * * See {ERC20-_burn}. */ function burn(uint256 amount) public virtual { _burn(_msgSender(), amount); } /** * @dev Destroys `amount` tokens from `account`, deducting from the caller's * allowance. * * See {ERC20-_burn} and {ERC20-allowance}. * * Requirements: * * - the caller must have allowance for `accounts`'s tokens of at least * `amount`. */ function burnFrom(address account, uint256 amount) public virtual { uint256 decreasedAllowance = allowance(account, _msgSender()).sub(amount, "ERC20: burn amount exceeds allowance"); _approve(account, _msgSender(), decreasedAllowance); _burn(account, amount); } /** * @dev Destroys `amount` tokens from `account`, reducing the * total supply. * * Emits a {Transfer} event with `to` set to the zero address. * * Requirements * * - `account` cannot be the zero address. * - `account` must have at least `amount` tokens. */ function _burn(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: burn from the zero address"); _beforeTokenTransfer(account, address(0), amount); _balances[account] = _balances[account].sub(amount, "ERC20: burn amount exceeds balance"); _totalSupply = _totalSupply.sub(amount); emit Transfer(account, address(0), amount); } /** * @dev Sets `amount` as the allowance of `spender` over the `owner`s tokens. * * This is internal function is equivalent to `approve`, and can be used to * e.g. set automatic allowances for certain subsystems, etc. * * Emits an {Approval} event. * * Requirements: * * - `owner` cannot be the zero address. * - `spender` cannot be the zero address. */ function _approve(address owner, address spender, uint256 amount) internal virtual { require(owner != address(0), "ERC20: approve from the zero address"); require(spender != address(0), "ERC20: approve to the zero address"); _allowances[owner][spender] = amount; emit Approval(owner, spender, amount); } /** * @dev Destroys `amount` tokens from `account`.`amount` is then deducted * from the caller's allowance. * * See {_burn} and {_approve}. */ function _burnFrom(address account, uint256 amount) internal virtual { _burn(account, amount); _approve(account, _msgSender(), _allowances[account][_msgSender()].sub(amount, "ERC20: burn amount exceeds allowance")); } /** * @dev Hook that is called before any transfer of tokens. This includes * minting and burning. * * Calling conditions: * * - when `from` and `to` are both non-zero, `amount` of `from`'s tokens * will be to transferred to `to`. * - when `from` is zero, `amount` tokens will be minted for `to`. * - when `to` is zero, `amount` of `from`'s tokens will be burned. * - `from` and `to` are never both zero. * * To learn more about hooks, head to xref:ROOT:using-hooks.adoc[Using Hooks]. */ function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual { } } // File contracts/ERC20/SafeERC20.sol /** * @title SafeERC20 * @dev Wrappers around ERC20 operations that throw on failure (when the token * contract returns false). Tokens that return no value (and instead revert or * throw on failure) are also supported, non-reverting calls are assumed to be * successful. * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. */ library SafeERC20 { using SafeMath for uint256; using Address for address; function safeTransfer(IERC20 token, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); } function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); } /** * @dev Deprecated. This function has issues similar to the ones found in * {IERC20-approve}, and its usage is discouraged. * * Whenever possible, use {safeIncreaseAllowance} and * {safeDecreaseAllowance} instead. */ function safeApprove(IERC20 token, address spender, uint256 value) internal { // safeApprove should only be called when setting an initial allowance, // or when resetting it to zero. To increase and decrease it, use // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' // solhint-disable-next-line max-line-length require((value == 0) || (token.allowance(address(this), spender) == 0), "SafeERC20: approve from non-zero to non-zero allowance" ); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); } function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal { uint256 newAllowance = token.allowance(address(this), spender).add(value); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal { uint256 newAllowance = token.allowance(address(this), spender).sub(value, "SafeERC20: decreased allowance below zero"); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). */ function _callOptionalReturn(IERC20 token, bytes memory data) private { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that // the target address contains contract code and also asserts for success in the low-level call. bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed"); if (returndata.length > 0) { // Return data is optional // solhint-disable-next-line max-line-length require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); } } } // File contracts/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/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/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/Curve/FraxCrossChainRewarder.sol // ==================================================================== // | ______ _______ | // | / _____________ __ __ / ____(_____ ____ _____ ________ | // | / /_ / ___/ __ `| |/_/ / /_ / / __ \/ __ `/ __ \/ ___/ _ \ | // | / __/ / / / /_/ _> < / __/ / / / / / /_/ / / / / /__/ __/ | // | /_/ /_/ \__,_/_/|_| /_/ /_/_/ /_/\__,_/_/ /_/\___/\___/ | // | | // ==================================================================== // ====================== FraxCrossChainRewarder ====================== // ==================================================================== // One-to-one relationship with a FraxMiddlemanGauge on the Ethereum mainnet // Because some bridges can only bridge to the exact same address on the other chain // This accepts bridged FXS rewards and then distributes them to the actual farm on this chain // 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 contract FraxCrossChainRewarder is Owned, ReentrancyGuard { using SafeMath for uint256; using SafeERC20 for ERC20; /* ========== STATE VARIABLES ========== */ // Instances and addresses address public reward_token_address; // Admin addresses address public timelock_address; address public curator_address; // Farm address address public farm_address; // Booleans bool public distributionsOn; /* ========== MODIFIERS ========== */ modifier onlyByOwnGov() { require(msg.sender == owner || msg.sender == timelock_address, "Not owner or timelock"); _; } modifier onlyByOwnerOrCuratorOrGovernance() { require(msg.sender == owner || msg.sender == curator_address || msg.sender == timelock_address, "Not owner, curator, or timelock"); _; } modifier isDistributing() { require(distributionsOn == true, "Distributions are off"); _; } /* ========== CONSTRUCTOR ========== */ constructor ( address _owner, address _curator_address, address _reward_token_address ) Owned(_owner) { curator_address = _curator_address; reward_token_address = _reward_token_address; distributionsOn = true; } /* ========== MUTATIVE FUNCTIONS ========== */ // Callable by anyone function distributeReward() public isDistributing nonReentrant returns (uint256 reward_balance) { // Get the reward balance reward_balance = ERC20(reward_token_address).balanceOf(address(this)); // Pay out the rewards directly to the farm TransferHelper.safeTransfer(reward_token_address, farm_address, reward_balance); emit RewardDistributed(farm_address, reward_balance); } /* ========== RESTRICTED FUNCTIONS - Curator / migrator callable ========== */ // For emergency situations function toggleDistributions() external onlyByOwnerOrCuratorOrGovernance { distributionsOn = !distributionsOn; emit DistributionsToggled(distributionsOn); } /* ========== RESTRICTED FUNCTIONS - Owner or timelock only ========== */ // 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 onlyByOwnGov { // Only the owner address can ever receive the recovery withdrawal TransferHelper.safeTransfer(tokenAddress, owner, tokenAmount); emit RecoveredERC20(tokenAddress, tokenAmount); } // Generic proxy function execute( address _to, uint256 _value, bytes calldata _data ) external onlyByOwnGov returns (bool, bytes memory) { (bool success, bytes memory result) = _to.call{value:_value}(_data); return (success, result); } function setFarmAddress(address _farm_address) external onlyByOwnGov { farm_address = _farm_address; emit FarmAddressChanged(farm_address); } function setTimelock(address _new_timelock) external onlyByOwnGov { timelock_address = _new_timelock; } function setCurator(address _new_curator_address) external onlyByOwnGov { curator_address = _new_curator_address; } /* ========== EVENTS ========== */ event RewardDistributed(address indexed farm_address, uint256 reward_amount); event RecoveredERC20(address token, uint256 amount); event FarmAddressChanged(address farm_address); event DistributionsToggled(bool distibutions_state); } // File contracts/ERC20/ERC20Permit/Counters.sol /** * @title Counters * @author Matt Condon (@shrugs) * @dev Provides counters that can only be incremented, decremented or reset. This can be used e.g. to track the number * of elements in a mapping, issuing ERC721 ids, or counting request ids. * * Include with `using Counters for Counters.Counter;` */ library Counters { struct Counter { // This variable should never be directly accessed by users of the library: interactions must be restricted to // the library's function. As of Solidity v0.5.2, this cannot be enforced, though there is a proposal to add // this feature: see https://github.com/ethereum/solidity/issues/4637 uint256 _value; // default: 0 } function current(Counter storage counter) internal view returns (uint256) { return counter._value; } function increment(Counter storage counter) internal { unchecked { counter._value += 1; } } function decrement(Counter storage counter) internal { uint256 value = counter._value; require(value > 0, "Counter: decrement overflow"); unchecked { counter._value = value - 1; } } function reset(Counter storage counter) internal { counter._value = 0; } } // File contracts/ERC20/ERC20Permit/ECDSA.sol /** * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations. * * These functions can be used to verify that a message was signed by the holder * of the private keys of a given address. */ library ECDSA { enum RecoverError { NoError, InvalidSignature, InvalidSignatureLength, InvalidSignatureS, InvalidSignatureV } function _throwError(RecoverError error) private pure { if (error == RecoverError.NoError) { return; // no error: do nothing } else if (error == RecoverError.InvalidSignature) { revert("ECDSA: invalid signature"); } else if (error == RecoverError.InvalidSignatureLength) { revert("ECDSA: invalid signature length"); } else if (error == RecoverError.InvalidSignatureS) { revert("ECDSA: invalid signature 's' value"); } else if (error == RecoverError.InvalidSignatureV) { revert("ECDSA: invalid signature 'v' value"); } } /** * @dev Returns the address that signed a hashed message (`hash`) with * `signature` or error string. This address can then be used for verification purposes. * * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures: * this function rejects them by requiring the `s` value to be in the lower * half order, and the `v` value to be either 27 or 28. * * IMPORTANT: `hash` _must_ be the result of a hash operation for the * verification to be secure: it is possible to craft signatures that * recover to arbitrary addresses for non-hashed data. A safe way to ensure * this is by receiving a hash of the original message (which may otherwise * be too long), and then calling {toEthSignedMessageHash} on it. * * Documentation for signature generation: * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js] * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers] * * _Available since v4.3._ */ function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) { // Check the signature length // - case 65: r,s,v signature (standard) // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._ if (signature.length == 65) { bytes32 r; bytes32 s; uint8 v; // ecrecover takes the signature parameters, and the only way to get them // currently is to use assembly. assembly { r := mload(add(signature, 0x20)) s := mload(add(signature, 0x40)) v := byte(0, mload(add(signature, 0x60))) } return tryRecover(hash, v, r, s); } else if (signature.length == 64) { bytes32 r; bytes32 vs; // ecrecover takes the signature parameters, and the only way to get them // currently is to use assembly. assembly { r := mload(add(signature, 0x20)) vs := mload(add(signature, 0x40)) } return tryRecover(hash, r, vs); } else { return (address(0), RecoverError.InvalidSignatureLength); } } /** * @dev Returns the address that signed a hashed message (`hash`) with * `signature`. This address can then be used for verification purposes. * * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures: * this function rejects them by requiring the `s` value to be in the lower * half order, and the `v` value to be either 27 or 28. * * IMPORTANT: `hash` _must_ be the result of a hash operation for the * verification to be secure: it is possible to craft signatures that * recover to arbitrary addresses for non-hashed data. A safe way to ensure * this is by receiving a hash of the original message (which may otherwise * be too long), and then calling {toEthSignedMessageHash} on it. */ function recover(bytes32 hash, bytes memory signature) internal pure returns (address) { (address recovered, RecoverError error) = tryRecover(hash, signature); _throwError(error); return recovered; } /** * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately. * * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures] * * _Available since v4.3._ */ function tryRecover( bytes32 hash, bytes32 r, bytes32 vs ) internal pure returns (address, RecoverError) { bytes32 s; uint8 v; assembly { s := and(vs, 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) v := add(shr(255, vs), 27) } return tryRecover(hash, v, r, s); } /** * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately. * * _Available since v4.2._ */ function recover( bytes32 hash, bytes32 r, bytes32 vs ) internal pure returns (address) { (address recovered, RecoverError error) = tryRecover(hash, r, vs); _throwError(error); return recovered; } /** * @dev Overload of {ECDSA-tryRecover} that receives the `v`, * `r` and `s` signature fields separately. * * _Available since v4.3._ */ function tryRecover( bytes32 hash, uint8 v, bytes32 r, bytes32 s ) internal pure returns (address, RecoverError) { // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most // signatures from current libraries generate a unique signature with an s-value in the lower half order. // // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept // these malleable signatures as well. if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) { return (address(0), RecoverError.InvalidSignatureS); } if (v != 27 && v != 28) { return (address(0), RecoverError.InvalidSignatureV); } // If the signature is valid (and not malleable), return the signer address address signer = ecrecover(hash, v, r, s); if (signer == address(0)) { return (address(0), RecoverError.InvalidSignature); } return (signer, RecoverError.NoError); } /** * @dev Overload of {ECDSA-recover} that receives the `v`, * `r` and `s` signature fields separately. */ function recover( bytes32 hash, uint8 v, bytes32 r, bytes32 s ) internal pure returns (address) { (address recovered, RecoverError error) = tryRecover(hash, v, r, s); _throwError(error); return recovered; } /** * @dev Returns an Ethereum Signed Message, created from a `hash`. This * produces hash corresponding to the one signed with the * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] * JSON-RPC method as part of EIP-191. * * See {recover}. */ function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) { // 32 is the length in bytes of hash, // enforced by the type signature above return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash)); } /** * @dev Returns an Ethereum Signed Typed Data, created from a * `domainSeparator` and a `structHash`. This produces hash corresponding * to the one signed with the * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`] * JSON-RPC method as part of EIP-712. * * See {recover}. */ function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) { return keccak256(abi.encodePacked("\x19\x01", domainSeparator, structHash)); } } // File contracts/ERC20/ERC20Permit/EIP712.sol /** * @dev https://eips.ethereum.org/EIPS/eip-712[EIP 712] is a standard for hashing and signing of typed structured data. * * The encoding specified in the EIP is very generic, and such a generic implementation in Solidity is not feasible, * thus this contract does not implement the encoding itself. Protocols need to implement the type-specific encoding * they need in their contracts using a combination of `abi.encode` and `keccak256`. * * This contract implements the EIP 712 domain separator ({_domainSeparatorV4}) that is used as part of the encoding * scheme, and the final step of the encoding to obtain the message digest that is then signed via ECDSA * ({_hashTypedDataV4}). * * The implementation of the domain separator was designed to be as efficient as possible while still properly updating * the chain id to protect against replay attacks on an eventual fork of the chain. * * NOTE: This contract implements the version of the encoding known as "v4", as implemented by the JSON RPC method * https://docs.metamask.io/guide/signing-data.html[`eth_signTypedDataV4` in MetaMask]. * * _Available since v3.4._ */ abstract contract EIP712 { /* solhint-disable var-name-mixedcase */ // Cache the domain separator as an immutable value, but also store the chain id that it corresponds to, in order to // invalidate the cached domain separator if the chain id changes. bytes32 private immutable _CACHED_DOMAIN_SEPARATOR; uint256 private immutable _CACHED_CHAIN_ID; bytes32 private immutable _HASHED_NAME; bytes32 private immutable _HASHED_VERSION; bytes32 private immutable _TYPE_HASH; /* solhint-enable var-name-mixedcase */ /** * @dev Initializes the domain separator and parameter caches. * * The meaning of `name` and `version` is specified in * https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator[EIP 712]: * * - `name`: the user readable name of the signing domain, i.e. the name of the DApp or the protocol. * - `version`: the current major version of the signing domain. * * NOTE: These parameters cannot be changed except through a xref:learn::upgrading-smart-contracts.adoc[smart * contract upgrade]. */ constructor(string memory name, string memory version) { bytes32 hashedName = keccak256(bytes(name)); bytes32 hashedVersion = keccak256(bytes(version)); bytes32 typeHash = keccak256( "EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)" ); _HASHED_NAME = hashedName; _HASHED_VERSION = hashedVersion; _CACHED_CHAIN_ID = block.chainid; _CACHED_DOMAIN_SEPARATOR = _buildDomainSeparator(typeHash, hashedName, hashedVersion); _TYPE_HASH = typeHash; } /** * @dev Returns the domain separator for the current chain. */ function _domainSeparatorV4() internal view returns (bytes32) { if (block.chainid == _CACHED_CHAIN_ID) { return _CACHED_DOMAIN_SEPARATOR; } else { return _buildDomainSeparator(_TYPE_HASH, _HASHED_NAME, _HASHED_VERSION); } } function _buildDomainSeparator( bytes32 typeHash, bytes32 nameHash, bytes32 versionHash ) private view returns (bytes32) { return keccak256(abi.encode(typeHash, nameHash, versionHash, block.chainid, address(this))); } /** * @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this * function returns the hash of the fully encoded EIP712 message for this domain. * * This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example: * * ```solidity * bytes32 digest = _hashTypedDataV4(keccak256(abi.encode( * keccak256("Mail(address to,string contents)"), * mailTo, * keccak256(bytes(mailContents)) * ))); * address signer = ECDSA.recover(digest, signature); * ``` */ function _hashTypedDataV4(bytes32 structHash) internal view virtual returns (bytes32) { return ECDSA.toTypedDataHash(_domainSeparatorV4(), structHash); } } // File contracts/ERC20/ERC20Permit/IERC20Permit.sol /** * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. * * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't * need to send a transaction, and thus is not required to hold Ether at all. */ interface IERC20Permit { /** * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens, * given ``owner``'s signed approval. * * IMPORTANT: The same issues {IERC20-approve} has related to transaction * ordering also apply here. * * Emits an {Approval} event. * * Requirements: * * - `spender` cannot be the zero address. * - `deadline` must be a timestamp in the future. * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` * over the EIP712-formatted function arguments. * - the signature must use ``owner``'s current nonce (see {nonces}). * * For more information on the signature format, see the * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP * section]. */ function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external; /** * @dev Returns the current nonce for `owner`. This value must be * included whenever a signature is generated for {permit}. * * Every successful call to {permit} increases ``owner``'s nonce by one. This * prevents a signature from being used multiple times. */ function nonces(address owner) external view returns (uint256); /** * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}. */ // solhint-disable-next-line func-name-mixedcase function DOMAIN_SEPARATOR() external view returns (bytes32); } // File contracts/ERC20/ERC20Permit/ERC20Permit.sol /** * @dev Implementation of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. * * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by * presenting a message signed by the account. By not relying on `{IERC20-approve}`, the token holder account doesn't * need to send a transaction, and thus is not required to hold Ether at all. * * _Available since v3.4._ */ abstract contract ERC20Permit is ERC20, IERC20Permit, EIP712 { using Counters for Counters.Counter; mapping(address => Counters.Counter) private _nonces; // solhint-disable-next-line var-name-mixedcase bytes32 private immutable _PERMIT_TYPEHASH = keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"); /** * @dev Initializes the {EIP712} domain separator using the `name` parameter, and setting `version` to `"1"`. * * It's a good idea to use the same `name` that is defined as the ERC20 token name. */ constructor(string memory name) EIP712(name, "1") {} /** * @dev See {IERC20Permit-permit}. */ function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) public virtual override { require(block.timestamp <= deadline, "ERC20Permit: expired deadline"); bytes32 structHash = keccak256(abi.encode(_PERMIT_TYPEHASH, owner, spender, value, _useNonce(owner), deadline)); bytes32 hash = _hashTypedDataV4(structHash); address signer = ECDSA.recover(hash, v, r, s); require(signer == owner, "ERC20Permit: invalid signature"); _approve(owner, spender, value); } /** * @dev See {IERC20Permit-nonces}. */ function nonces(address owner) public view virtual override returns (uint256) { return _nonces[owner].current(); } /** * @dev See {IERC20Permit-DOMAIN_SEPARATOR}. */ // solhint-disable-next-line func-name-mixedcase function DOMAIN_SEPARATOR() external view override returns (bytes32) { return _domainSeparatorV4(); } function PERMIT_TYPEHASH() external view returns (bytes32) { return _PERMIT_TYPEHASH; } /** * @dev "Consume a nonce": return the current value and increment. * * _Available since v4.1._ */ function _useNonce(address owner) internal virtual returns (uint256 current) { Counters.Counter storage nonce = _nonces[owner]; current = nonce.current(); nonce.increment(); } } // File contracts/ERC20/__CROSSCHAIN/CrossChainCanonical.sol // ==================================================================== // | ______ _______ | // | / _____________ __ __ / ____(_____ ____ _____ ________ | // | / /_ / ___/ __ `| |/_/ / /_ / / __ \/ __ `/ __ \/ ___/ _ \ | // | / __/ / / / /_/ _> < / __/ / / / / / /_/ / / / / /__/ __/ | // | /_/ /_/ \__,_/_/|_| /_/ /_/_/ /_/\__,_/_/ /_/\___/\___/ | // | | // ==================================================================== // ======================== CrossChainCanonical ======================= // ==================================================================== // Cross-chain / non mainnet canonical token contract. // Can accept any number of old non-canonical tokens. These will be // withdrawable by the owner so they can de-bridge it and get back mainnet 'real' tokens // Does not include any spurious mainnet logic // 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 contract CrossChainCanonical is ERC20Permit, Owned, ReentrancyGuard { using SafeMath for uint256; /* ========== STATE VARIABLES ========== */ // Core address public timelock_address; // Governance timelock address address public custodian_address; // Misc uint256 public mint_cap; mapping(address => uint256[2]) public swap_fees; mapping(address => bool) public fee_exempt_list; // Acceptable old tokens address[] public bridge_tokens_array; mapping(address => bool) public bridge_tokens; // The addresses in this array are able to mint tokens address[] public minters_array; mapping(address => bool) public minters; // Mapping is also used for faster verification // Constants for various precisions uint256 private constant PRICE_PRECISION = 1e6; // Administrative booleans bool public exchangesPaused; // Pause old token exchanges in case of an emergency mapping(address => bool) public canSwap; /* ========== MODIFIERS ========== */ modifier onlyByOwnGov() { require(msg.sender == timelock_address || msg.sender == owner, "Not owner or timelock"); _; } modifier onlyByOwnGovCust() { require(msg.sender == timelock_address || msg.sender == owner || msg.sender == custodian_address, "Not owner, tlck, or custd"); _; } modifier onlyMinters() { require(minters[msg.sender], "Not a minter"); _; } modifier onlyMintersOwnGov() { require(_isMinterOwnGov(msg.sender), "Not minter, owner, or tlck"); _; } modifier validBridgeToken(address token_address) { require(bridge_tokens[token_address], "Invalid old token"); _; } /* ========== CONSTRUCTOR ========== */ constructor ( string memory _name, string memory _symbol, address _creator_address, uint256 _initial_mint_amt, address _custodian_address, address[] memory _bridge_tokens ) ERC20(_name, _symbol) ERC20Permit(_name) Owned(_creator_address) { custodian_address = _custodian_address; // Initialize the starting old tokens for (uint256 i = 0; i < _bridge_tokens.length; i++){ // Mark as accepted bridge_tokens[_bridge_tokens[i]] = true; // Add to the array bridge_tokens_array.push(_bridge_tokens[i]); // Set a small swap fee initially of 0.04% swap_fees[_bridge_tokens[i]] = [400, 400]; // Make sure swapping is on canSwap[_bridge_tokens[i]] = true; } // Set the mint cap to the initial mint amount mint_cap = _initial_mint_amt; // Mint some canonical tokens to the creator super._mint(_creator_address, _initial_mint_amt); } /* ========== VIEWS ========== */ // Helpful for UIs function allBridgeTokens() external view returns (address[] memory) { return bridge_tokens_array; } function _isMinterOwnGov(address the_address) internal view returns (bool) { return (the_address == timelock_address || the_address == owner || minters[the_address]); } function _isFeeExempt(address the_address) internal view returns (bool) { return (_isMinterOwnGov(the_address) || fee_exempt_list[the_address]); } /* ========== INTERNAL FUNCTIONS ========== */ // Enforce a minting cap function _mint_capped(address account, uint256 amount) internal { require(totalSupply() + amount <= mint_cap, "Mint cap"); super._mint(account, amount); } /* ========== PUBLIC FUNCTIONS ========== */ // Exchange old or bridge tokens for these canonical tokens function exchangeOldForCanonical(address bridge_token_address, uint256 token_amount) external nonReentrant validBridgeToken(bridge_token_address) returns (uint256 canonical_tokens_out) { require(!exchangesPaused && canSwap[bridge_token_address], "Exchanges paused"); // Pull in the old / bridge tokens TransferHelper.safeTransferFrom(bridge_token_address, msg.sender, address(this), token_amount); // Handle the fee, if applicable canonical_tokens_out = token_amount; if (!_isFeeExempt(msg.sender)) { canonical_tokens_out -= ((canonical_tokens_out * swap_fees[bridge_token_address][0]) / PRICE_PRECISION); } // Mint canonical tokens and give it to the sender _mint_capped(msg.sender, canonical_tokens_out); } // Exchange canonical tokens for old or bridge tokens function exchangeCanonicalForOld(address bridge_token_address, uint256 token_amount) external nonReentrant validBridgeToken(bridge_token_address) returns (uint256 bridge_tokens_out) { require(!exchangesPaused && canSwap[bridge_token_address], "Exchanges paused"); // Burn the canonical tokens super._burn(msg.sender, token_amount); // Handle the fee, if applicable bridge_tokens_out = token_amount; if (!_isFeeExempt(msg.sender)) { bridge_tokens_out -= ((bridge_tokens_out * swap_fees[bridge_token_address][1]) / PRICE_PRECISION); } // Give old / bridge tokens to the sender TransferHelper.safeTransfer(bridge_token_address, msg.sender, bridge_tokens_out); } /* ========== MINTERS OR GOVERNANCE FUNCTIONS ========== */ // Collect old / bridge tokens so you can de-bridge them back on mainnet function withdrawBridgeTokens(address bridge_token_address, uint256 bridge_token_amount) external onlyMintersOwnGov validBridgeToken(bridge_token_address) { TransferHelper.safeTransfer(bridge_token_address, msg.sender, bridge_token_amount); } /* ========== MINTERS ONLY ========== */ // This function is what other minters will call to mint new tokens function minter_mint(address m_address, uint256 m_amount) external onlyMinters { _mint_capped(m_address, m_amount); emit TokenMinted(msg.sender, m_address, m_amount); } // This function is what other minters will call to burn tokens function minter_burn(uint256 amount) external onlyMinters { super._burn(msg.sender, amount); emit TokenBurned(msg.sender, amount); } /* ========== RESTRICTED FUNCTIONS, BUT CUSTODIAN CAN CALL TOO ========== */ function toggleExchanges() external onlyByOwnGovCust { exchangesPaused = !exchangesPaused; } /* ========== RESTRICTED FUNCTIONS ========== */ function addBridgeToken(address bridge_token_address, uint256 _brdg_to_can_fee, uint256 _can_to_brdg_fee) external onlyByOwnGov { // Make sure the token is not already present for (uint i = 0; i < bridge_tokens_array.length; i++){ if (bridge_tokens_array[i] == bridge_token_address){ revert("Token already present"); } } // Add the old token bridge_tokens[bridge_token_address] = true; bridge_tokens_array.push(bridge_token_address); // Turn swapping on canSwap[bridge_token_address] = true; // Set the fees swap_fees[bridge_token_address][0] = _brdg_to_can_fee; swap_fees[bridge_token_address][1] = _can_to_brdg_fee; emit BridgeTokenAdded(bridge_token_address); } function toggleBridgeToken(address bridge_token_address) external onlyByOwnGov { // Make sure the token is already present in the array bool bridge_tkn_found; for (uint i = 0; i < bridge_tokens_array.length; i++){ if (bridge_tokens_array[i] == bridge_token_address){ bridge_tkn_found = true; break; } } require(bridge_tkn_found, "Bridge tkn not in array"); // Toggle the token bridge_tokens[bridge_token_address] = !bridge_tokens[bridge_token_address]; // Toggle swapping canSwap[bridge_token_address] = !canSwap[bridge_token_address]; emit BridgeTokenToggled(bridge_token_address, !bridge_tokens[bridge_token_address]); } // Adds a minter address function addMinter(address minter_address) external onlyByOwnGov { require(minter_address != address(0), "Zero address detected"); require(minters[minter_address] == false, "Address already exists"); minters[minter_address] = true; minters_array.push(minter_address); emit MinterAdded(minter_address); } // Remove a minter function removeMinter(address minter_address) external onlyByOwnGov { require(minter_address != address(0), "Zero address detected"); require(minters[minter_address] == true, "Address nonexistent"); // Delete from the mapping delete minters[minter_address]; // 'Delete' from the array by setting the address to 0x0 for (uint i = 0; i < minters_array.length; i++){ if (minters_array[i] == minter_address) { minters_array[i] = address(0); // This will leave a null in the array and keep the indices the same break; } } emit MinterRemoved(minter_address); } function setMintCap(uint256 _mint_cap) external onlyByOwnGov { mint_cap = _mint_cap; emit MintCapSet(_mint_cap); } function setSwapFees(address bridge_token_address, uint256 _bridge_to_canonical, uint256 _canonical_to_old) external onlyByOwnGov { swap_fees[bridge_token_address] = [_bridge_to_canonical, _canonical_to_old]; } function toggleFeesForAddress(address the_address) external onlyByOwnGov { fee_exempt_list[the_address] = !fee_exempt_list[the_address]; } function setTimelock(address new_timelock) external onlyByOwnGov { require(new_timelock != address(0), "Zero address detected"); timelock_address = new_timelock; emit TimelockSet(new_timelock); } function setCustodian(address _custodian_address) external onlyByOwnGov { require(_custodian_address != address(0), "Zero address detected"); custodian_address = _custodian_address; emit CustodianSet(_custodian_address); } function recoverERC20(address tokenAddress, uint256 tokenAmount) external onlyByOwnGov { require(!bridge_tokens[tokenAddress], "Cannot withdraw bridge tokens"); require(tokenAddress != address(this), "Cannot withdraw these tokens"); TransferHelper.safeTransfer(address(tokenAddress), msg.sender, tokenAmount); } // // Generic proxy // function execute( // address _to, // uint256 _value, // bytes calldata _data // ) external onlyByOwnGov returns (bool, bytes memory) { // (bool success, bytes memory result) = _to.call{value:_value}(_data); // return (success, result); // } /* ========== EVENTS ========== */ event TokenBurned(address indexed from, uint256 amount); event TokenMinted(address indexed from, address indexed to, uint256 amount); event BridgeTokenAdded(address indexed bridge_token_address); event BridgeTokenToggled(address indexed bridge_token_address, bool state); event MinterAdded(address pool_address); event MinterRemoved(address pool_address); event MintCapSet(uint256 new_mint_cap); event TimelockSet(address new_timelock); event CustodianSet(address custodian_address); } // File contracts/ERC20/__CROSSCHAIN/CrossChainCanonicalFXS.sol contract CrossChainCanonicalFXS is CrossChainCanonical { constructor ( string memory _name, string memory _symbol, address _creator_address, uint256 _initial_mint_amt, address _custodian_address, address[] memory _bridge_tokens ) CrossChainCanonical(_name, _symbol, _creator_address, _initial_mint_amt, _custodian_address, _bridge_tokens) {} } // File contracts/Curve/IveFXS.sol 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/ERC20/__CROSSCHAIN/IanyFXS.sol interface IanyFXS { function DOMAIN_SEPARATOR() external view returns (bytes32); function PERMIT_TYPEHASH() external view returns (bytes32); function Swapin(bytes32 txhash, address account, uint256 amount) external returns (bool); function Swapout(uint256 amount, address bindaddr) external returns (bool); function TRANSFER_TYPEHASH() external view returns (bytes32); function allowance(address, address) external view returns (uint256); function approve(address spender, uint256 value) external returns (bool); function approveAndCall(address spender, uint256 value, bytes calldata data) external returns (bool); function balanceOf(address) external view returns (uint256); function burn(address from, uint256 amount) external returns (bool); function changeMPCOwner(address newVault) external returns (bool); function changeVault(address newVault) external returns (bool); function decimals() external view returns (uint8); function deposit(uint256 amount, address to) external returns (uint256); function deposit(uint256 amount) external returns (uint256); function deposit() external returns (uint256); function depositVault(uint256 amount, address to) external returns (uint256); function depositWithPermit(address target, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s, address to) external returns (uint256); function depositWithTransferPermit(address target, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s, address to) external returns (uint256); function mint(address to, uint256 amount) external returns (bool); function name() external view returns (string memory); function nonces(address) external view returns (uint256); function owner() external view returns (address); function permit(address target, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) external; function symbol() external view returns (string memory); function totalSupply() external view returns (uint256); function transfer(address to, uint256 value) external returns (bool); function transferAndCall(address to, uint256 value, bytes calldata data) external returns (bool); function transferFrom(address from, address to, uint256 value) external returns (bool); function transferWithPermit(address target, address to, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) external returns (bool); function underlying() external view returns (address); function vault() external view returns (address); function withdraw(uint256 amount, address to) external returns (uint256); function withdraw(uint256 amount) external returns (uint256); function withdraw() external returns (uint256); function withdrawVault(address from, uint256 amount, address to) external returns (uint256); } // File contracts/Misc_AMOs/saddle/ISaddleLPToken.sol interface ISaddleLPToken { function allowance( address owner, address spender) external view returns (uint256); function approve( address spender, uint256 amount) external returns (bool); function balanceOf( address account) external view returns (uint256); function burn( uint256 amount) external; function burnFrom( address account, uint256 amount) external; function decimals( ) external view returns (uint8); function decreaseAllowance( address spender, uint256 subtractedValue) external returns (bool); function increaseAllowance( address spender, uint256 addedValue) external returns (bool); function initialize( string memory name, string memory symbol) external returns (bool); function mint( address recipient, uint256 amount) external; function name( ) external view returns (string memory); function owner( ) external view returns (address); function renounceOwnership( ) external; function symbol( ) external view returns (string memory); function totalSupply( ) external view returns (uint256); function transfer( address recipient, uint256 amount) external returns (bool); function transferFrom( address sender, address recipient, uint256 amount) external returns (bool); function transferOwnership( address newOwner) external; } // File contracts/Misc_AMOs/saddle/ISaddlePermissionlessSwap.sol interface ISaddlePermissionlessSwap { function FEE_COLLECTOR_NAME () external view returns (bytes32); function MASTER_REGISTRY () external view returns (address); function addLiquidity (uint256[] memory amounts, uint256 minToMint, uint256 deadline) external returns (uint256); function calculateRemoveLiquidity (uint256 amount) external view returns (uint256[] memory); function calculateRemoveLiquidityOneToken (uint256 tokenAmount, uint8 tokenIndex) external view returns (uint256 availableTokenAmount); function calculateSwap (uint8 tokenIndexFrom, uint8 tokenIndexTo, uint256 dx) external view returns (uint256); function calculateTokenAmount (uint256[] memory amounts, bool deposit) external view returns (uint256); function feeCollector () external view returns (address); function getA () external view returns (uint256); function getAPrecise () external view returns (uint256); function getAdminBalance (uint256 index) external view returns (uint256); function getToken (uint8 index) external view returns (address); function getTokenBalance (uint8 index) external view returns (uint256); function getTokenIndex (address tokenAddress) external view returns (uint8); function getVirtualPrice () external view returns (uint256); function initialize (address[] memory _pooledTokens, uint8[] memory decimals, string memory lpTokenName, string memory lpTokenSymbol, uint256 _a, uint256 _fee, uint256 _adminFee, address lpTokenTargetAddress) external; function owner () external view returns (address); function pause () external; function paused () external view returns (bool); function rampA (uint256 futureA, uint256 futureTime) external; function removeLiquidity (uint256 amount, uint256[] memory minAmounts, uint256 deadline) external returns (uint256[] memory); function removeLiquidityImbalance (uint256[] memory amounts, uint256 maxBurnAmount, uint256 deadline) external returns (uint256); function removeLiquidityOneToken (uint256 tokenAmount, uint8 tokenIndex, uint256 minAmount, uint256 deadline) external returns (uint256); function renounceOwnership () external; function setAdminFee (uint256 newAdminFee) external; function setSwapFee (uint256 newSwapFee) external; function stopRampA () external; function swap (uint8 tokenIndexFrom, uint8 tokenIndexTo, uint256 dx, uint256 minDy, uint256 deadline) external returns (uint256); function swapStorage () external view returns (uint256 initialA, uint256 futureA, uint256 initialATime, uint256 futureATime, uint256 swapFee, uint256 adminFee, address lpToken); function transferOwnership (address newOwner) external; function unpause () external; function updateFeeCollectorCache () external; function withdrawAdminFees () external; } // File contracts/Staking/FraxCrossChainFarmV3.sol // ==================================================================== // | ______ _______ | // | / _____________ __ __ / ____(_____ ____ _____ ________ | // | / /_ / ___/ __ `| |/_/ / /_ / / __ \/ __ `/ __ \/ ___/ _ \ | // | / __/ / / / /_/ _> < / __/ / / / / / /_/ / / / / /__/ __/ | // | /_/ /_/ \__,_/_/|_| /_/ /_/_/ /_/\__,_/_/ /_/\___/\___/ | // | | // ==================================================================== // ======================= FraxCrossChainFarmV3 ======================= // ==================================================================== // No veFXS logic // Because of lack of cross-chain reading of the gauge controller's emission rate, // the contract sets its reward based on its token balance(s) // Rolling 7 day reward period idea credit goes to denett // rewardRate0 and rewardRate1 will look weird as people claim, but if you track the rewards actually emitted, // the numbers do check out // V3: Accepts canonicalFXS directly from Fraxferry and does not swap out // Frax Finance: https://github.com/FraxFinance // Primary Author(s) // Travis Moore: https://github.com/FortisFortuna // Reviewer(s) / Contributor(s) // Sam Kazemian: https://github.com/samkazemian // Dennis: github.com/denett // Originally inspired by Synthetix.io, but heavily modified by the Frax team // https://raw.githubusercontent.com/Synthetixio/synthetix/develop/contracts/StakingRewards.sol // import '../Misc_AMOs/curve/I2pool.sol'; // Curve 2-token // import '../Misc_AMOs/curve/I3pool.sol'; // Curve 3-token // import '../Misc_AMOs/mstable/IFeederPool.sol'; // mStable // import '../Misc_AMOs/impossible/IStableXPair.sol'; // Impossible // import '../Misc_AMOs/mstable/IFeederPool.sol'; // mStable // Inheritance contract FraxCrossChainFarmV3 is Owned, ReentrancyGuard { using SafeMath for uint256; using SafeERC20 for ERC20; /* ========== STATE VARIABLES ========== */ // Instances IveFXS public veFXS; CrossChainCanonicalFXS public rewardsToken0; // Assumed to be canFXS ERC20 public rewardsToken1; // I2pool public stakingToken; // Curve 2-token // I3pool public stakingToken; // Curve 3-token // IStableXPair public stakingToken; // Impossible // IFeederPool public stakingToken; // mStable ISaddleLPToken public stakingToken; // Saddle L2D4 // ILPToken public stakingToken; // Snowball S4D // IUniswapV2Pair public stakingToken; // Uniswap V2 FraxCrossChainRewarder public rewarder; // FRAX address public frax_address; // Constant for various precisions uint256 private constant MULTIPLIER_PRECISION = 1e18; // Admin addresses address public timelock_address; // Governance timelock address address public controller_address; // Gauge controller // Time tracking uint256 public periodFinish; uint256 public lastUpdateTime; // Lock time and multiplier settings uint256 public lock_max_multiplier = uint256(3e18); // E18. 1x = e18 uint256 public lock_time_for_max_multiplier = 3 * 365 * 86400; // 3 years uint256 public lock_time_min = 86400; // 1 * 86400 (1 day) // veFXS related uint256 public vefxs_per_frax_for_max_boost = uint256(4e18); // E18. 4e18 means 4 veFXS must be held by the staker per 1 FRAX uint256 public vefxs_max_multiplier = uint256(2e18); // E18. 1x = 1e18 mapping(address => uint256) private _vefxsMultiplierStored; // Max reward per second uint256 public rewardRate0; uint256 public rewardRate1; // Reward period uint256 public rewardsDuration = 604800; // 7 * 86400 (7 days). // Reward tracking uint256 public ttlRew0Owed; uint256 public ttlRew1Owed; uint256 public ttlRew0Paid; uint256 public ttlRew1Paid; uint256 private rewardPerTokenStored0; uint256 private rewardPerTokenStored1; mapping(address => uint256) public userRewardPerTokenPaid0; mapping(address => uint256) public userRewardPerTokenPaid1; mapping(address => uint256) public rewards0; mapping(address => uint256) public rewards1; uint256 public lastRewardPull; mapping(address => uint256) internal lastRewardClaimTime; // staker addr -> timestamp // Balance tracking uint256 private _total_liquidity_locked; uint256 private _total_combined_weight; mapping(address => uint256) private _locked_liquidity; mapping(address => uint256) private _combined_weights; // Uniswap V2 / Impossible ONLY bool frax_is_token0; // Stake tracking mapping(address => LockedStake[]) public lockedStakes; // List of valid migrators (set by governance) mapping(address => bool) public valid_migrators; // Stakers set which migrator(s) they want to use mapping(address => mapping(address => bool)) public staker_allowed_migrators; // Administrative booleans bool public migrationsOn; // Used for migrations. Prevents new stakes, but allows LP and reward withdrawals bool public stakesUnlocked; // Release locked stakes in case of system migration or emergency bool public withdrawalsPaused; // For emergencies bool public rewardsCollectionPaused; // For emergencies bool public stakingPaused; // For emergencies bool public isInitialized; /* ========== STRUCTS ========== */ struct LockedStake { bytes32 kek_id; uint256 start_timestamp; uint256 liquidity; uint256 ending_timestamp; uint256 lock_multiplier; // 6 decimals of precision. 1x = 1000000 } /* ========== MODIFIERS ========== */ modifier onlyByOwnGov() { require(msg.sender == owner || msg.sender == timelock_address, "Not owner or timelock"); _; } modifier onlyByOwnGovCtrlr() { require(msg.sender == owner || msg.sender == timelock_address || msg.sender == controller_address, "Not own, tlk, or ctrlr"); _; } modifier isMigrating() { require(migrationsOn == true, "Not in migration"); _; } modifier notStakingPaused() { require(stakingPaused == false, "Staking paused"); _; } modifier updateRewardAndBalance(address account, bool sync_too) { _updateRewardAndBalance(account, sync_too); _; } /* ========== CONSTRUCTOR ========== */ constructor ( address _owner, address _rewardsToken0, address _rewardsToken1, address _stakingToken, address _frax_address, address _timelock_address, address _rewarder_address ) Owned(_owner){ frax_address = _frax_address; rewardsToken0 = CrossChainCanonicalFXS(_rewardsToken0); rewardsToken1 = ERC20(_rewardsToken1); // stakingToken = I2pool(_stakingToken); // stakingToken = I3pool(_stakingToken); // stakingToken = IStableXPair(_stakingToken); // stakingToken = IFeederPool(_stakingToken); stakingToken = ISaddleLPToken(_stakingToken); // stakingToken = ILPToken(_stakingToken); // stakingToken = IUniswapV2Pair(_stakingToken); timelock_address = _timelock_address; rewarder = FraxCrossChainRewarder(_rewarder_address); // Uniswap V2 / Impossible ONLY // Need to know which token FRAX is (0 or 1) // address token0 = stakingToken.token0(); // if (token0 == frax_address) frax_is_token0 = true; // else frax_is_token0 = false; // Other booleans migrationsOn = false; stakesUnlocked = false; // For initialization lastUpdateTime = block.timestamp; periodFinish = block.timestamp.add(rewardsDuration); } /* ========== VIEWS ========== */ // Total locked liquidity tokens function totalLiquidityLocked() external view returns (uint256) { return _total_liquidity_locked; } // Locked liquidity for a given account function lockedLiquidityOf(address account) external view returns (uint256) { return _locked_liquidity[account]; } // 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 totalCombinedWeight() external view returns (uint256) { return _total_combined_weight; } // Combined weight for a specific account function combinedWeightOf(address account) external view returns (uint256) { return _combined_weights[account]; } // All the locked stakes for a given account function lockedStakesOf(address account) external view returns (LockedStake[] memory) { return lockedStakes[account]; } 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 ) ; } function lastTimeRewardApplicable() internal view returns (uint256) { return Math.min(block.timestamp, periodFinish); } function fraxPerLPToken() public view returns (uint256) { // Get the amount of FRAX 'inside' of the lp tokens uint256 frax_per_lp_token; // // Curve 2-token // // ============================================ // { // address coin0 = stakingToken.coins(0); // uint256 total_frax_reserves; // if (coin0 == frax_address) { // total_frax_reserves = stakingToken.balances(0); // } // else { // total_frax_reserves = stakingToken.balances(1); // } // frax_per_lp_token = total_frax_reserves.mul(1e18).div(stakingToken.totalSupply()); // } // // Curve 3-token // // ============================================ // { // address coin0 = stakingToken.coins(0); // address coin1 = stakingToken.coins(1); // uint256 total_frax_reserves; // if (coin0 == frax_address) { // total_frax_reserves = stakingToken.balances(0); // } // else if (coin1 == frax_address) { // total_frax_reserves = stakingToken.balances(1); // } // else { // total_frax_reserves = stakingToken.balances(2); // } // frax_per_lp_token = total_frax_reserves.mul(1e18).div(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.mul(1e18).div(stakingToken.totalSupply()); // } // Saddle L2D4 // ============================================ { ISaddlePermissionlessSwap ISPS = ISaddlePermissionlessSwap(0xF2839E0b30B5e96083085F498b14bbc12530b734); uint256 total_frax = ISPS.getTokenBalance(ISPS.getTokenIndex(frax_address)); frax_per_lp_token = total_frax.mul(1e18).div(stakingToken.totalSupply()); } // Most Saddles / Snowball S4D // ============================================ // { // ISwapFlashLoan ISFL = ISwapFlashLoan(0xfeEa4D1BacB0519E8f952460A70719944fe56Ee0); // uint256 total_frax = ISFL.getTokenBalance(ISFL.getTokenIndex(frax_address)); // frax_per_lp_token = total_frax.mul(1e18).div(stakingToken.totalSupply()); // } // Uniswap V2 & Impossible // ============================================ // { // 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.mul(1e18).div(stakingToken.totalSupply()); // } return frax_per_lp_token; } function userStakedFrax(address account) public view returns (uint256) { return (fraxPerLPToken()).mul(_locked_liquidity[account]).div(1e18); } function minVeFXSForMaxBoost(address account) public view returns (uint256) { return (userStakedFrax(account)).mul(vefxs_per_frax_for_max_boost).div(MULTIPLIER_PRECISION); } function veFXSMultiplier(address account) public view returns (uint256) { if (address(veFXS) != address(0)){ // The claimer gets a boost depending on amount of veFXS they have relative to the amount of FRAX 'inside' // of their locked LP tokens uint256 veFXS_needed_for_max_boost = minVeFXSForMaxBoost(account); if (veFXS_needed_for_max_boost > 0){ uint256 user_vefxs_fraction = (veFXS.balanceOf(account)).mul(MULTIPLIER_PRECISION).div(veFXS_needed_for_max_boost); uint256 vefxs_multiplier = ((user_vefxs_fraction).mul(vefxs_max_multiplier)).div(MULTIPLIER_PRECISION); // Cap the boost to the vefxs_max_multiplier if (vefxs_multiplier > vefxs_max_multiplier) vefxs_multiplier = vefxs_max_multiplier; return vefxs_multiplier; } else return 0; // This will happen with the first stake, when user_staked_frax is 0 } else return 0; } 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 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; } } function rewardPerToken() public view returns (uint256, uint256) { if (_total_liquidity_locked == 0 || _total_combined_weight == 0) { return (rewardPerTokenStored0, rewardPerTokenStored1); } else { return ( rewardPerTokenStored0.add( lastTimeRewardApplicable().sub(lastUpdateTime).mul(rewardRate0).mul(1e18).div(_total_combined_weight) ), rewardPerTokenStored1.add( lastTimeRewardApplicable().sub(lastUpdateTime).mul(rewardRate1).mul(1e18).div(_total_combined_weight) ) ); } } function earned(address account) public view returns (uint256, uint256) { (uint256 rew_per_token0, uint256 rew_per_token1) = rewardPerToken(); if (_combined_weights[account] == 0){ return (0, 0); } return ( (_combined_weights[account].mul(rew_per_token0.sub(userRewardPerTokenPaid0[account]))).div(1e18).add(rewards0[account]), (_combined_weights[account].mul(rew_per_token1.sub(userRewardPerTokenPaid1[account]))).div(1e18).add(rewards1[account]) ); } function getRewardForDuration() external view returns (uint256, uint256) { return ( rewardRate0.mul(rewardsDuration), rewardRate1.mul(rewardsDuration) ); } /* ========== MUTATIVE FUNCTIONS ========== */ 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"); } function _updateRewardAndBalance(address account, bool sync_too) internal { // Need to retro-adjust some things if the period hasn't been renewed, then start a new one if (sync_too){ sync(); } if (account != address(0)) { // To keep the math correct, the user's combined weight must be recomputed to account for their // ever-changing veFXS balance. ( uint256 old_combined_weight, uint256 new_vefxs_multiplier, uint256 new_combined_weight ) = calcCurCombinedWeight(account); // Calculate the earnings first _syncEarned(account); // Update the user's stored veFXS multipliers _vefxsMultiplierStored[account] = new_vefxs_multiplier; // Update the user's and the global combined weights if (new_combined_weight >= old_combined_weight) { uint256 weight_diff = new_combined_weight.sub(old_combined_weight); _total_combined_weight = _total_combined_weight.add(weight_diff); _combined_weights[account] = old_combined_weight.add(weight_diff); } else { uint256 weight_diff = old_combined_weight.sub(new_combined_weight); _total_combined_weight = _total_combined_weight.sub(weight_diff); _combined_weights[account] = old_combined_weight.sub(weight_diff); } } } // Add additional LPs to an existing locked stake function lockAdditional(bytes32 kek_id, uint256 addl_liq) updateRewardAndBalance(msg.sender, true) public { // Get the stake and its index (LockedStake memory thisStake, uint256 theArrayIndex) = _getStake(msg.sender, kek_id); // Calculate the new amount uint256 new_amt = thisStake.liquidity + addl_liq; // Checks require(addl_liq >= 0, "Must be nonzero"); // Pull the tokens from the sender TransferHelper.safeTransferFrom(address(stakingToken), msg.sender, address(this), addl_liq); // Update the stake lockedStakes[msg.sender][theArrayIndex] = LockedStake( kek_id, thisStake.start_timestamp, new_amt, thisStake.ending_timestamp, thisStake.lock_multiplier ); // Update liquidities _total_liquidity_locked += addl_liq; _locked_liquidity[msg.sender] += addl_liq; // 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 updateRewardAndBalance(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); } function _syncEarned(address account) internal { if (account != address(0)) { // Calculate the earnings (uint256 earned0, uint256 earned1) = earned(account); rewards0[account] = earned0; rewards1[account] = earned1; userRewardPerTokenPaid0[account] = rewardPerTokenStored0; userRewardPerTokenPaid1[account] = rewardPerTokenStored1; } } // Staker can allow a migrator function stakerAllowMigrator(address migrator_address) external { require(valid_migrators[migrator_address], "Invalid migrator address"); staker_allowed_migrators[msg.sender][migrator_address] = true; } // Staker can disallow a previously-allowed migrator function stakerDisallowMigrator(address migrator_address) external { // Delete from the mapping delete staker_allowed_migrators[msg.sender][migrator_address]; } // Two different stake functions are needed because of delegateCall and msg.sender issues (important for migration) function stakeLocked(uint256 liquidity, uint256 secs) nonReentrant public { _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 updateRewardAndBalance(staker_address, true) { require(!stakingPaused || valid_migrators[msg.sender] == true, "Staking paused or in migration"); require(liquidity > 0, "Must stake more than zero"); require(secs >= lock_time_min, "Minimum stake time not met"); require(secs <= lock_time_for_max_multiplier,"Trying to lock for too long"); uint256 lock_multiplier = lockMultiplier(secs); bytes32 kek_id = keccak256(abi.encodePacked(staker_address, start_timestamp, liquidity, _locked_liquidity[staker_address])); lockedStakes[staker_address].push(LockedStake( kek_id, start_timestamp, liquidity, start_timestamp.add(secs), lock_multiplier )); // Pull the tokens from the source_address TransferHelper.safeTransferFrom(address(stakingToken), source_address, address(this), liquidity); // Update liquidities _total_liquidity_locked = _total_liquidity_locked.add(liquidity); _locked_liquidity[staker_address] = _locked_liquidity[staker_address].add(liquidity); // Need to call to update the combined weights _updateRewardAndBalance(staker_address, false); emit StakeLocked(staker_address, liquidity, secs, kek_id, source_address); } // Two different withdrawLocked functions are needed because of delegateCall and msg.sender issues (important for migration) function withdrawLocked(bytes32 kek_id) nonReentrant public { require(withdrawalsPaused == false, "Withdrawals paused"); _withdrawLocked(msg.sender, msg.sender, kek_id); } // No withdrawer == msg.sender check needed since this is only internally callable and the checks are done in the wrapper // functions like withdraw(), migrator_withdraw_unlocked() and migrator_withdraw_locked() function _withdrawLocked(address staker_address, address destination_address, bytes32 kek_id) internal { // Collect rewards first and then update the balances _getReward(staker_address, destination_address); (LockedStake memory thisStake, uint256 theArrayIndex) = _getStake(staker_address, kek_id); require(thisStake.kek_id == kek_id, "Stake not found"); require(block.timestamp >= thisStake.ending_timestamp || stakesUnlocked == true || valid_migrators[msg.sender] == true, "Stake is still locked!"); uint256 liquidity = thisStake.liquidity; if (liquidity > 0) { // Update liquidities _total_liquidity_locked = _total_liquidity_locked.sub(liquidity); _locked_liquidity[staker_address] = _locked_liquidity[staker_address].sub(liquidity); // Remove the stake from the array delete lockedStakes[staker_address][theArrayIndex]; // Need to call to update the combined weights _updateRewardAndBalance(staker_address, false); // Give the tokens to the destination_address // Should throw if insufficient balance stakingToken.transfer(destination_address, liquidity); emit WithdrawLocked(staker_address, liquidity, kek_id, destination_address); } } // Two different getReward functions are needed because of delegateCall and msg.sender issues (important for migration) function getReward() external nonReentrant returns (uint256, uint256) { require(rewardsCollectionPaused == false,"Rewards collection paused"); return _getReward(msg.sender, msg.sender); } // No withdrawer == msg.sender check needed since this is only internally callable // This distinction is important for the migrator function _getReward(address rewardee, address destination_address) internal updateRewardAndBalance(rewardee, true) returns (uint256 reward0, uint256 reward1) { reward0 = rewards0[rewardee]; reward1 = rewards1[rewardee]; if (reward0 > 0) { rewards0[rewardee] = 0; rewardsToken0.transfer(destination_address, reward0); ttlRew0Paid += reward0; emit RewardPaid(rewardee, reward0, address(rewardsToken0), destination_address); } if (reward1 > 0) { rewards1[rewardee] = 0; rewardsToken1.transfer(destination_address, reward1); ttlRew1Paid += reward1; emit RewardPaid(rewardee, reward1, address(rewardsToken1), destination_address); } // Update the last reward claim time lastRewardClaimTime[rewardee] = block.timestamp; } // Quasi-notifyRewardAmount() logic function syncRewards() internal { // Bring in rewards, if applicable if ((address(rewarder) != address(0)) && ((block.timestamp).sub(lastRewardPull) >= rewardsDuration)){ rewarder.distributeReward(); lastRewardPull = block.timestamp; } // Get the current reward token balances uint256 curr_bal_0 = rewardsToken0.balanceOf(address(this)); uint256 curr_bal_1 = rewardsToken1.balanceOf(address(this)); // Update the owed amounts based off the old reward rates // Anything over a week is zeroed { uint256 eligible_elapsed_time = Math.min((block.timestamp).sub(lastUpdateTime), rewardsDuration); ttlRew0Owed += rewardRate0.mul(eligible_elapsed_time); ttlRew1Owed += rewardRate1.mul(eligible_elapsed_time); } // Update the stored amounts too { (uint256 reward0, uint256 reward1) = rewardPerToken(); rewardPerTokenStored0 = reward0; rewardPerTokenStored1 = reward1; } // Set the reward rates based on the free amount of tokens { // Don't count unpaid rewards as free uint256 unpaid0 = ttlRew0Owed.sub(ttlRew0Paid); uint256 unpaid1 = ttlRew1Owed.sub(ttlRew1Paid); // Handle reward token0 if (curr_bal_0 <= unpaid0){ // token0 is depleted, so stop emitting rewardRate0 = 0; } else { uint256 free0 = curr_bal_0.sub(unpaid0); rewardRate0 = (free0).div(rewardsDuration); } // Handle reward token1 if (curr_bal_1 <= unpaid1){ // token1 is depleted, so stop emitting rewardRate1 = 0; } else { uint256 free1 = curr_bal_1.sub(unpaid1); rewardRate1 = (free1).div(rewardsDuration); } } } function sync() public { require(isInitialized, "Contract not initialized"); // Swap bridge tokens // Make sure the rewardRates are synced to the current FXS balance syncRewards(); // Rolling 7 days rewards period lastUpdateTime = block.timestamp; periodFinish = (block.timestamp).add(rewardsDuration); } /* ========== RESTRICTED FUNCTIONS ========== */ // Needed when first deploying the farm // Make sure rewards are present function initializeDefault() external onlyByOwnGovCtrlr { require(!isInitialized, "Already initialized"); isInitialized = true; // Bring in rewards, if applicable if (address(rewarder) != address(0)){ rewarder.distributeReward(); lastRewardPull = block.timestamp; } emit DefaultInitialization(); } // Migrator can stake for someone else (they won't be able to withdraw it back though, only staker_address can). function migrator_stakeLocked_for(address staker_address, uint256 amount, uint256 secs, uint256 start_timestamp) external isMigrating { require(staker_allowed_migrators[staker_address][msg.sender] && valid_migrators[msg.sender], "Mig. invalid or unapproved"); _stakeLocked(staker_address, msg.sender, amount, secs, start_timestamp); } // Used for migrations function migrator_withdraw_locked(address staker_address, bytes32 kek_id) external isMigrating { require(staker_allowed_migrators[staker_address][msg.sender] && valid_migrators[msg.sender], "Mig. invalid or unapproved"); _withdrawLocked(staker_address, msg.sender, kek_id); } // Adds supported migrator address function addMigrator(address migrator_address) external onlyByOwnGov { valid_migrators[migrator_address] = true; } // Remove a migrator address function removeMigrator(address migrator_address) external onlyByOwnGov { require(valid_migrators[migrator_address] == true, "Address nonexistent"); // Delete from the mapping delete valid_migrators[migrator_address]; } // 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 onlyByOwnGov { // Admin cannot withdraw the staking token from the contract unless currently migrating if(!migrationsOn){ require(tokenAddress != address(stakingToken), "Not in migration"); // Only Governance / Timelock can trigger a migration } // Only the owner address can ever receive the recovery withdrawal ERC20(tokenAddress).transfer(owner, tokenAmount); emit Recovered(tokenAddress, tokenAmount); } function setMultipliers(uint256 _lock_max_multiplier, uint256 _vefxs_max_multiplier, uint256 _vefxs_per_frax_for_max_boost) external onlyByOwnGov { require(_lock_max_multiplier >= MULTIPLIER_PRECISION, "Mult must be >= MULTIPLIER_PRECISION"); require(_vefxs_max_multiplier >= 0, "veFXS mul must be >= 0"); require(_vefxs_per_frax_for_max_boost > 0, "veFXS pct max must be >= 0"); lock_max_multiplier = _lock_max_multiplier; vefxs_max_multiplier = _vefxs_max_multiplier; vefxs_per_frax_for_max_boost = _vefxs_per_frax_for_max_boost; emit MaxVeFXSMultiplier(vefxs_max_multiplier); emit LockedStakeMaxMultiplierUpdated(lock_max_multiplier); emit veFXSPerFraxForMaxBoostUpdated(vefxs_per_frax_for_max_boost); } function setLockedStakeTimeForMinAndMaxMultiplier(uint256 _lock_time_for_max_multiplier, uint256 _lock_time_min) external onlyByOwnGov { require(_lock_time_for_max_multiplier >= 1, "Mul max time must be >= 1"); require(_lock_time_min >= 1, "Mul min time must be >= 1"); lock_time_for_max_multiplier = _lock_time_for_max_multiplier; lock_time_min = _lock_time_min; emit LockedStakeTimeForMaxMultiplier(lock_time_for_max_multiplier); emit LockedStakeMinTime(_lock_time_min); } function unlockStakes() external onlyByOwnGov { stakesUnlocked = !stakesUnlocked; } function toggleMigrations() external onlyByOwnGov { migrationsOn = !migrationsOn; } function toggleStaking() external onlyByOwnGov { stakingPaused = !stakingPaused; } function toggleWithdrawals() external onlyByOwnGov { withdrawalsPaused = !withdrawalsPaused; } function toggleRewardsCollection() external onlyByOwnGov { rewardsCollectionPaused = !rewardsCollectionPaused; } function setTimelock(address _new_timelock) external onlyByOwnGov { timelock_address = _new_timelock; } function setController(address _controller_address) external onlyByOwnGov { controller_address = _controller_address; } function setVeFXS(address _vefxs_address) external onlyByOwnGov { veFXS = IveFXS(_vefxs_address); } /* ========== EVENTS ========== */ event StakeLocked(address indexed user, uint256 amount, uint256 secs, bytes32 kek_id, address source_address); event WithdrawLocked(address indexed user, uint256 amount, bytes32 kek_id, address destination_address); event RewardPaid(address indexed user, uint256 reward, address token_address, address destination_address); event DefaultInitialization(); event Recovered(address token, uint256 amount); event LockedStakeMaxMultiplierUpdated(uint256 multiplier); event LockedStakeTimeForMaxMultiplier(uint256 secs); event LockedStakeMinTime(uint256 secs); 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 MaxVeFXSMultiplier(uint256 multiplier); event veFXSPerFraxForMaxBoostUpdated(uint256 scale_factor); } // File contracts/Staking/Variants/FraxCCFarmV3_ArbiSaddleL2D4.sol contract FraxCCFarmV3_ArbiSaddleL2D4 is FraxCrossChainFarmV3 { constructor ( address _owner, address _rewardsToken0, address _rewardsToken1, address _stakingToken, address _frax_address, address _timelock_address, address _rewarder_address ) FraxCrossChainFarmV3(_owner, _rewardsToken0, _rewardsToken1, _stakingToken, _frax_address, _timelock_address, _rewarder_address) {} }
[{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address","name":"_rewardsToken0","type":"address"},{"internalType":"address","name":"_rewardsToken1","type":"address"},{"internalType":"address","name":"_stakingToken","type":"address"},{"internalType":"address","name":"_frax_address","type":"address"},{"internalType":"address","name":"_timelock_address","type":"address"},{"internalType":"address","name":"_rewarder_address","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[],"name":"DefaultInitialization","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":"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":"uint256","name":"multiplier","type":"uint256"}],"name":"LockedStakeMaxMultiplierUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"secs","type":"uint256"}],"name":"LockedStakeMinTime","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"secs","type":"uint256"}],"name":"LockedStakeTimeForMaxMultiplier","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"multiplier","type":"uint256"}],"name":"MaxVeFXSMultiplier","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":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Recovered","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"reward","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":"amount","type":"uint256"},{"indexed":false,"internalType":"bytes32","name":"kek_id","type":"bytes32"},{"indexed":false,"internalType":"address","name":"destination_address","type":"address"}],"name":"WithdrawLocked","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"scale_factor","type":"uint256"}],"name":"veFXSPerFraxForMaxBoostUpdated","type":"event"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"migrator_address","type":"address"}],"name":"addMigrator","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":"account","type":"address"}],"name":"combinedWeightOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"controller_address","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"earned","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"fraxPerLPToken","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"frax_address","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getReward","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getRewardForDuration","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"initializeDefault","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"isInitialized","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastRewardPull","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 FraxCrossChainFarmV3.LockedStake[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"migrationsOn","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"staker_address","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"secs","type":"uint256"},{"internalType":"uint256","name":"start_timestamp","type":"uint256"}],"name":"migrator_stakeLocked_for","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"staker_address","type":"address"},{"internalType":"bytes32","name":"kek_id","type":"bytes32"}],"name":"migrator_withdraw_locked","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"minVeFXSForMaxBoost","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_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":"tokenAddress","type":"address"},{"internalType":"uint256","name":"tokenAmount","type":"uint256"}],"name":"recoverERC20","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"migrator_address","type":"address"}],"name":"removeMigrator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"rewardPerToken","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rewardRate0","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rewardRate1","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rewarder","outputs":[{"internalType":"contract FraxCrossChainRewarder","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"rewards0","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"rewards1","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rewardsCollectionPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rewardsDuration","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rewardsToken0","outputs":[{"internalType":"contract CrossChainCanonicalFXS","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rewardsToken1","outputs":[{"internalType":"contract ERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_controller_address","type":"address"}],"name":"setController","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_lock_time_for_max_multiplier","type":"uint256"},{"internalType":"uint256","name":"_lock_time_min","type":"uint256"}],"name":"setLockedStakeTimeForMinAndMaxMultiplier","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_lock_max_multiplier","type":"uint256"},{"internalType":"uint256","name":"_vefxs_max_multiplier","type":"uint256"},{"internalType":"uint256","name":"_vefxs_per_frax_for_max_boost","type":"uint256"}],"name":"setMultipliers","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_new_timelock","type":"address"}],"name":"setTimelock","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_vefxs_address","type":"address"}],"name":"setVeFXS","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"secs","type":"uint256"}],"name":"stakeLocked","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"migrator_address","type":"address"}],"name":"stakerAllowMigrator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"migrator_address","type":"address"}],"name":"stakerDisallowMigrator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"staker_allowed_migrators","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"stakesUnlocked","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"stakingPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"stakingToken","outputs":[{"internalType":"contract ISaddleLPToken","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"sync","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"timelock_address","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"toggleMigrations","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"toggleRewardsCollection","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"toggleStaking","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"toggleWithdrawals","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":"ttlRew0Owed","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ttlRew0Paid","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ttlRew1Owed","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ttlRew1Paid","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unlockStakes","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"userRewardPerTokenPaid0","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"userRewardPerTokenPaid1","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","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":"","type":"address"}],"name":"valid_migrators","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"veFXS","outputs":[{"internalType":"contract IveFXS","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"veFXSMultiplier","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"}],"name":"withdrawLocked","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"withdrawalsPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}]
Contract Creation Code
60806040526729a2241af62c0000600d556305a39a80600e5562015180600f55673782dace9d900000601055671bc16d674ec8000060115562093a806015553480156200004b57600080fd5b50604051620052d7380380620052d78339810160408190526200006e916200025e565b86868686868686866001600160a01b038116620000d25760405162461bcd60e51b815260206004820152601960248201527f4f776e657220616464726573732063616e6e6f7420626520300000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b03831690811782556040805192835260208301919091527fb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159c910160405180910390a1506001600255600880546001600160a01b03199081166001600160a01b038681169190911790925560048054821689841617905560058054821688841617905560068054821687841617905560098054821685841617905560078054909116918316919091179055602a805461ffff1916905542600c819055601554620001bd9190620001d5602090811b6200372817901c565b600b5550620003159c50505050505050505050505050565b600080620001e48385620002f3565b905083811015620002385760405162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f7700000000006044820152606401620000c9565b90505b92915050565b80516001600160a01b03811681146200025957600080fd5b919050565b600080600080600080600060e0888a0312156200027a57600080fd5b620002858862000241565b9650620002956020890162000241565b9550620002a56040890162000241565b9450620002b56060890162000241565b9350620002c56080890162000241565b9250620002d560a0890162000241565b9150620002e560c0890162000241565b905092959891949750929550565b808201808211156200023b57634e487b7160e01b600052601160045260246000fd5b614fb280620003256000396000f3fe608060405234801561001057600080fd5b50600436106105645760003560e01c80638980f11f116102d7578063cdc82e8011610186578063e9f2838e116100e3578063f288baf611610097578063fce6fd131161007c578063fce6fd1314610c0a578063fe271f5f14610c17578063fff6cae914610c3757600080fd5b8063f288baf614610bf8578063f2a8d34914610c0157600080fd5b8063ebe2b12b116100c8578063ebe2b12b14610bb9578063ee89e02f14610bc2578063f12f144714610be557600080fd5b8063e9f2838e14610b93578063eb3c209e14610ba657600080fd5b8063dc6663c71161013a578063e01f62bf1161011f578063e01f62bf14610b7a578063e1ba95d214610b82578063e239421814610b8a57600080fd5b8063dc6663c714610b3a578063dcc3e06e14610b5a57600080fd5b8063d2fbdc0d1161016b578063d2fbdc0d14610ade578063d42fc9b414610af1578063d9f96e8d14610b0457600080fd5b8063cdc82e8014610acd578063d239f00314610ad657600080fd5b8063af00f4e211610234578063c0cd318a116101e8578063c69fd222116101cd578063c69fd22214610a9c578063c8f33c9114610abc578063cd3daf9d14610ac557600080fd5b8063c0cd318a14610a73578063c126d1aa14610a7c57600080fd5b8063b94c4dcb11610219578063b94c4dcb14610a42578063bbb781cc14610a4b578063bdacb30314610a6057600080fd5b8063af00f4e214610a1c578063b85efd0614610a2f57600080fd5b80639b8c15a81161028b578063a1ec508a11610270578063a1ec508a14610a02578063a2217bc514610a0b578063aca4f78714610a1357600080fd5b80639b8c15a8146109c15780639c5303eb146109ef57600080fd5b80638da5cb5b116102bc5780638da5cb5b1461097c57806392eefe9b1461099c5780639637927f146109af57600080fd5b80638980f11f1461093b5780638bad86a71461094e57600080fd5b80633b8105b3116104335780636a231b0311610390578063774d4ae71161034457806379ba50971161032957806379ba50971461090b5780637b31c19a146109135780638950b9a61461091b57600080fd5b8063774d4ae7146108bd5780637970833e146108d057600080fd5b80636cea0b0d116103755780636cea0b0d1461088b5780636e27cef91461089457806372f702f31461089d57600080fd5b80636a231b03146108585780636ce46bc31461087857600080fd5b806353a47bb7116103e75780635e0ddd52116103cc5780635e0ddd521461082757806364f2c0601461083057806367feda3e1461083857600080fd5b806353a47bb7146107ff5780635bfd92581461081f57600080fd5b80634fd2b536116104185780634fd2b5361461077257806351e3fc171461078557806352732bc81461079857600080fd5b80633b8105b3146107625780633d18b9121461076a57600080fd5b80631b3e870a116104e15780632ca1a8951161049557806336f89af21161047a57806336f89af21461070d578063386a952514610743578063392e53cd1461074c57600080fd5b80632ca1a895146106e0578063323331ca146106e957600080fd5b80631e090f01116104c65780631e090f011461069a57806328ef934e146106ba5780632c0c2a0a146106cd57600080fd5b80631b3e870a1461067f5780631c1f78eb1461069257600080fd5b8063144e803411610538578063169d27ef1161051d578063169d27ef1461064457806317b18c891461064c57806319ff52fd1461065f57600080fd5b8063144e8034146106115780631627540c1461063157600080fd5b80628cc26214610569578063046e7d3f146105965780630a25ef4b146105ab5780630d7bac4f146105f0575b600080fd5b61057c610577366004614bf9565b610c3f565b604080519283526020830191909152015b60405180910390f35b6105a96105a4366004614bf9565b610da2565b005b6008546105cb9073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161058d565b6106036105fe366004614c14565b610e91565b60405190815260200161058d565b61060361061f366004614bf9565b601c6020526000908152604090205481565b6105a961063f366004614bf9565b610ebd565b6105a9610fdd565b6105a961065a366004614c2d565b61122a565b6003546105cb9073ffffffffffffffffffffffffffffffffffffffff1681565b6105a961068d366004614bf9565b6112af565b61057c611432565b6106ad6106a8366004614bf9565b611463565b60405161058d9190614c4f565b6105a96106c8366004614cbd565b611517565b6106036106db366004614bf9565b611650565b61060360135481565b602a546106fd906301000000900460ff1681565b604051901515815260200161058d565b61060361071b366004614bf9565b73ffffffffffffffffffffffffffffffffffffffff1660009081526025602052604090205490565b61060360155481565b602a546106fd9065010000000000900460ff1681565b6105a9611788565b61057c611868565b610603610780366004614bf9565b611965565b6105a9610793366004614c14565b611982565b6105a96107a6366004614bf9565b33600090815260296020908152604080832073ffffffffffffffffffffffffffffffffffffffff9490941683529290522080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055565b6001546105cb9073ffffffffffffffffffffffffffffffffffffffff1681565b610603611a77565b61060360175481565b602354610603565b600a546105cb9073ffffffffffffffffffffffffffffffffffffffff1681565b610603610866366004614bf9565b601f6020526000908152604090205481565b6105a9610886366004614cf6565b611c50565b61060360205481565b610603600f5481565b6006546105cb9073ffffffffffffffffffffffffffffffffffffffff1681565b6106036108cb366004614d22565b611eb1565b6108e36108de366004614d22565b6120bd565b604080519586526020860194909452928401919091526060830152608082015260a00161058d565b6105a961210b565b6105a9612256565b6005546105cb9073ffffffffffffffffffffffffffffffffffffffff1681565b6105a9610949366004614d22565b612335565b61096161095c366004614bf9565b612559565b6040805193845260208401929092529082015260600161058d565b6000546105cb9073ffffffffffffffffffffffffffffffffffffffff1681565b6105a96109aa366004614bf9565b61278d565b602a546106fd90610100900460ff1681565b6106fd6109cf366004614d4c565b602960209081526000928352604080842090915290825290205460ff1681565b6105a96109fd366004614bf9565b612877565b61060360145481565b6105a9612969565b61060360185481565b6105a9610a2a366004614c2d565b612a3e565b6105a9610a3d366004614c2d565b612c24565b610603600e5481565b602a546106fd90640100000000900460ff1681565b6105a9610a6e366004614bf9565b612d9b565b61060360165481565b610603610a8a366004614bf9565b601e6020526000908152604090205481565b6004546105cb9073ffffffffffffffffffffffffffffffffffffffff1681565b610603600c5481565b61057c612e85565b610603600d5481565b6105a9612f14565b6105a9610aec366004614c2d565b612ff2565b610603610aff366004614bf9565b613356565b610603610b12366004614bf9565b73ffffffffffffffffffffffffffffffffffffffff1660009081526024602052604090205490565b6009546105cb9073ffffffffffffffffffffffffffffffffffffffff1681565b6007546105cb9073ffffffffffffffffffffffffffffffffffffffff1681565b602254610603565b6105a9613396565b61060360195481565b602a546106fd9062010000900460ff1681565b6105a9610bb4366004614d22565b613473565b610603600b5481565b6106fd610bd0366004614bf9565b60286020526000908152604090205460ff1681565b6105a9610bf3366004614bf9565b6135a8565b61060360115481565b61060360105481565b602a546106fd9060ff1681565b610603610c25366004614bf9565b601d6020526000908152604090205481565b6105a9613693565b600080600080610c4d612e85565b73ffffffffffffffffffffffffffffffffffffffff871660009081526025602052604081205492945090925003610c8b575060009485945092505050565b73ffffffffffffffffffffffffffffffffffffffff85166000908152601e6020908152604080832054601c90925290912054610d179190610d1190670de0b6b3a764000090610d0b90610cdf9088906137a8565b73ffffffffffffffffffffffffffffffffffffffff8b16600090815260256020526040902054906137ea565b906138a2565b90613728565b73ffffffffffffffffffffffffffffffffffffffff86166000908152601f6020908152604080832054601d90925290912054610d979190610d1190670de0b6b3a764000090610d0b90610d6b9088906137a8565b73ffffffffffffffffffffffffffffffffffffffff8c16600090815260256020526040902054906137ea565b935093505050915091565b60005473ffffffffffffffffffffffffffffffffffffffff16331480610ddf575060095473ffffffffffffffffffffffffffffffffffffffff1633145b610e4a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b000000000000000000000060448201526064015b60405180910390fd5b600380547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b600d54600e54600091610eb791610ea88286614dae565b610eb29190614dc5565b6138e4565b92915050565b60005473ffffffffffffffffffffffffffffffffffffffff163314610f64576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602f60248201527f4f6e6c792074686520636f6e7472616374206f776e6572206d6179207065726660448201527f6f726d207468697320616374696f6e00000000000000000000000000000000006064820152608401610e41565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040519081527f906a1c6bd7e3091ea86693dd029a831c19049ce77f1dce2ce0bab1cacbabce229060200160405180910390a150565b60005473ffffffffffffffffffffffffffffffffffffffff1633148061101a575060095473ffffffffffffffffffffffffffffffffffffffff1633145b8061103c5750600a5473ffffffffffffffffffffffffffffffffffffffff1633145b6110a2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4e6f74206f776e2c20746c6b2c206f72206374726c72000000000000000000006044820152606401610e41565b602a5465010000000000900460ff1615611118576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f416c726561647920696e697469616c697a6564000000000000000000000000006044820152606401610e41565b602a80547fffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffffff166501000000000017905560075473ffffffffffffffffffffffffffffffffffffffff16156111ff57600760009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16638f73c5ae6040518163ffffffff1660e01b81526004016020604051808303816000875af11580156111d5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111f99190614e00565b50426020555b6040517fb5cfe3ccd03847076864f081609024cbc2eb98c38da4d8b2cebe9479a9a1ef3790600090a1565b6002805403611295576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610e41565b600280556112a633808484426138fa565b50506001600255565b60005473ffffffffffffffffffffffffffffffffffffffff163314806112ec575060095473ffffffffffffffffffffffffffffffffffffffff1633145b611352576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b00000000000000000000006044820152606401610e41565b73ffffffffffffffffffffffffffffffffffffffff811660009081526028602052604090205460ff1615156001146113e6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f41646472657373206e6f6e6578697374656e74000000000000000000000000006044820152606401610e41565b73ffffffffffffffffffffffffffffffffffffffff16600090815260286020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055565b60008061144c6015546013546137ea90919063ffffffff16565b60155460145461145b916137ea565b915091509091565b73ffffffffffffffffffffffffffffffffffffffff81166000908152602760209081526040808320805482518185028101850190935280835260609492939192909184015b8282101561150c57838290600052602060002090600502016040518060a001604052908160008201548152602001600182015481526020016002820154815260200160038201548152602001600482015481525050815260200190600101906114a8565b505050509050919050565b602a5460ff161515600114611588576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f4e6f7420696e206d6967726174696f6e000000000000000000000000000000006044820152606401610e41565b73ffffffffffffffffffffffffffffffffffffffff8416600090815260296020908152604080832033845290915290205460ff1680156115d757503360009081526028602052604090205460ff165b61163d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f4d69672e20696e76616c6964206f7220756e617070726f7665640000000000006044820152606401610e41565b61164a84338585856138fa565b50505050565b60035460009073ffffffffffffffffffffffffffffffffffffffff161561177b57600061167c83611965565b90508015611772576003546040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8581166004830152600092611734928592610d0b92670de0b6b3a7640000929116906370a0823190602401602060405180830381865afa15801561170a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061172e9190614e00565b906137ea565b90506000611759670de0b6b3a7640000610d0b601154856137ea90919063ffffffff16565b905060115481111561176a57506011545b949350505050565b50600092915050565b506000919050565b919050565b60005473ffffffffffffffffffffffffffffffffffffffff163314806117c5575060095473ffffffffffffffffffffffffffffffffffffffff1633145b61182b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b00000000000000000000006044820152606401610e41565b602a80547fffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffff81166401000000009182900460ff1615909102179055565b60008060028054036118d6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610e41565b60028055602a546301000000900460ff161561194e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f5265776172647320636f6c6c656374696f6e20706175736564000000000000006044820152606401610e41565b6119583333613d30565b9150915060016002559091565b6000610eb7670de0b6b3a7640000610d0b60105461172e86613356565b60028054036119ed576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610e41565b60028055602a5462010000900460ff1615611a64576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f5769746864726177616c732070617573656400000000000000000000000000006044820152606401610e41565b611a6f333383614006565b506001600255565b6008546040517f66c0bd2400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9091166004820152600090819073f2839e0b30b5e96083085f498b14bbc12530b73490829082906391ceb3eb9082906366c0bd2490602401602060405180830381865afa158015611b0a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b2e9190614e19565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b16815260ff9091166004820152602401602060405180830381865afa158015611b84573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ba89190614e00565b905061176a600660009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611c1a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c3e9190614e00565b610d0b83670de0b6b3a76400006137ea565b60005473ffffffffffffffffffffffffffffffffffffffff16331480611c8d575060095473ffffffffffffffffffffffffffffffffffffffff1633145b611cf3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b00000000000000000000006044820152606401610e41565b670de0b6b3a7640000831015611d8a576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f4d756c74206d757374206265203e3d204d554c5449504c4945525f505245434960448201527f53494f4e000000000000000000000000000000000000000000000000000000006064820152608401610e41565b60008111611df4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f766546585320706374206d6178206d757374206265203e3d20300000000000006044820152606401610e41565b600d839055601182905560108190556040518281527fc9d56ccdd6b954d8d74700db074cc667054f8e33c1b8d23e97021d4c588a87619060200160405180910390a17fa1676084a9eea08c6f205b60799323b364a1bd8e10aba89f0fbd94cfbf68b5dd600d54604051611e6991815260200190565b60405180910390a17f58c7ececaeb4704a0039e0d22c1b618367f7a7b9a4e191ab9baed34898f63f2e601054604051611ea491815260200190565b60405180910390a1505050565b73ffffffffffffffffffffffffffffffffffffffff82166000908152602760205260408120805482919084908110611eeb57611eeb614e3c565b600091825260208083206040805160a081018252600590940290910180548452600181015484840181905260028201548584015260038201546060860152600490910154608085015273ffffffffffffffffffffffffffffffffffffffff8916855260219092528320549193501115611f6957506020810151611f91565b5073ffffffffffffffffffffffffffffffffffffffff84166000908152602160205260409020545b4282606001511161205157606082015173ffffffffffffffffffffffffffffffffffffffff86166000908152602160205260409020541015612048576000818360600151611fdf9190614e6b565b90506000836060015142611ff39190614e6b565b905060006120056105fe600285614dc5565b905060006120138382614dae565b61201d8584614dae565b6120279190614e7e565b90506120338385614e7e565b61203d9082614dc5565b9650505050506120a1565b600092506120a1565b6000808284606001516120649190614e6b565b905060004285606001516120789190614e6b565b905060026120868284614e7e565b6120909190614dc5565b9250505061209d81610e91565b9350505b81608001518311156120b557816080015192505b505092915050565b602760205281600052604060002081815481106120d957600080fd5b600091825260209091206005909102018054600182015460028301546003840154600490940154929550909350919085565b60015473ffffffffffffffffffffffffffffffffffffffff1633146121b2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603560248201527f596f75206d757374206265206e6f6d696e61746564206265666f726520796f7560448201527f2063616e20616363657074206f776e65727368697000000000000000000000006064820152608401610e41565b6000546001546040805173ffffffffffffffffffffffffffffffffffffffff93841681529290911660208301527fb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159c910160405180910390a160018054600080547fffffffffffffffffffffffff000000000000000000000000000000000000000090811673ffffffffffffffffffffffffffffffffffffffff841617909155169055565b60005473ffffffffffffffffffffffffffffffffffffffff16331480612293575060095473ffffffffffffffffffffffffffffffffffffffff1633145b6122f9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b00000000000000000000006044820152606401610e41565b602a80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffff811663010000009182900460ff1615909102179055565b60005473ffffffffffffffffffffffffffffffffffffffff16331480612372575060095473ffffffffffffffffffffffffffffffffffffffff1633145b6123d8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b00000000000000000000006044820152606401610e41565b602a5460ff166124675760065473ffffffffffffffffffffffffffffffffffffffff90811690831603612467576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f4e6f7420696e206d6967726174696f6e000000000000000000000000000000006044820152606401610e41565b6000546040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9182166004820152602481018390529083169063a9059cbb906044016020604051808303816000875af11580156124e0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125049190614e91565b506040805173ffffffffffffffffffffffffffffffffffffffff84168152602081018390527f8c1256b8896378cd5044f80c202f9772b9d77dc85c8a6eb51967210b09bfaa2891015b60405180910390a15050565b73ffffffffffffffffffffffffffffffffffffffff8116600090815260256020526040812054908061258a84611650565b73ffffffffffffffffffffffffffffffffffffffff8516600090815260246020526040812054919350901580156125e4575073ffffffffffffffffffffffffffffffffffffffff8516600090815260256020526040902054155b80612614575073ffffffffffffffffffffffffffffffffffffffff85166000908152601260205260409020548310155b15612620575081612660565b73ffffffffffffffffffffffffffffffffffffffff85166000908152601260205260409020546002906126539085614e7e565b61265d9190614dc5565b90505b6000915060005b73ffffffffffffffffffffffffffffffffffffffff86166000908152602760205260409020548110156127845773ffffffffffffffffffffffffffffffffffffffff861660009081526027602052604081208054839081106126cb576126cb614e3c565b90600052602060002090600502016040518060a001604052908160008201548152602001600182015481526020016002820154815260200160038201548152602001600482015481525050905060006127248884611eb1565b60408301519091506000670de0b6b3a76400006127418785614e7e565b61274b9084614dae565b6127559190614dc5565b61275f9083614e7e565b905061276b8188614e7e565b965050505050808061277c90614eb3565b915050612667565b50509193909250565b60005473ffffffffffffffffffffffffffffffffffffffff163314806127ca575060095473ffffffffffffffffffffffffffffffffffffffff1633145b612830576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b00000000000000000000006044820152606401610e41565b600a80547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b60005473ffffffffffffffffffffffffffffffffffffffff163314806128b4575060095473ffffffffffffffffffffffffffffffffffffffff1633145b61291a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b00000000000000000000006044820152606401610e41565b73ffffffffffffffffffffffffffffffffffffffff16600090815260286020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b60005473ffffffffffffffffffffffffffffffffffffffff163314806129a6575060095473ffffffffffffffffffffffffffffffffffffffff1633145b612a0c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b00000000000000000000006044820152606401610e41565b602a80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00811660ff90911615179055565b60005473ffffffffffffffffffffffffffffffffffffffff16331480612a7b575060095473ffffffffffffffffffffffffffffffffffffffff1633145b612ae1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b00000000000000000000006044820152606401610e41565b6001821015612b4c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f4d756c206d61782074696d65206d757374206265203e3d2031000000000000006044820152606401610e41565b6001811015612bb7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f4d756c206d696e2074696d65206d757374206265203e3d2031000000000000006044820152606401610e41565b600e829055600f8190556040518281527f0e3e3fae480c6f92291358a02bc83f04ee1971d5488596bffda7929d57ab470f9060200160405180910390a16040518181527f0534d208d75dfdbfacc1204745dd9b3c4c37e8cfc05eb5e8e3ae538aedb0a9fa9060200161254d565b336001612c3182826142fa565b600080612c3e338761441d565b915091506000858360400151612c549190614e7e565b9050600654612c7b9073ffffffffffffffffffffffffffffffffffffffff163330896145e2565b6040805160a081018252888152602085810151818301528183018490526060808701519083015260808087015190830152336000908152602790915291909120805484908110612ccd57612ccd614e3c565b906000526020600020906005020160008201518160000155602082015181600101556040820151816002015560608201518160030155608082015181600401559050508560226000828254612d229190614e7e565b90915550503360009081526024602052604081208054889290612d46908490614e7e565b90915550612d5790503360006142fa565b604080518881526020810188905233917f2640b32e7e5d0fa2a21ea06b22fbd75fda0fda384a895a5fdeef43646de47a0c910160405180910390a250505050505050565b60005473ffffffffffffffffffffffffffffffffffffffff16331480612dd8575060095473ffffffffffffffffffffffffffffffffffffffff1633145b612e3e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b00000000000000000000006044820152606401610e41565b600980547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b60008060225460001480612e995750602354155b15612eaa575050601a54601b549091565b612ee2612ed9602354610d0b670de0b6b3a764000061172e60135461172e600c54612ed3614778565b906137a8565b601a5490613728565b61145b612f0b602354610d0b670de0b6b3a764000061172e60145461172e600c54612ed3614778565b601b5490613728565b60005473ffffffffffffffffffffffffffffffffffffffff16331480612f51575060095473ffffffffffffffffffffffffffffffffffffffff1633145b612fb7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b00000000000000000000006044820152606401610e41565b602a80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffff8116620100009182900460ff1615909102179055565b600280540361305d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610e41565b6002805533600161306e82826142fa565b60008061307b338761441d565b915091504285116130e8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4d75737420626520696e207468652066757475726500000000000000000000006044820152606401610e41565b6000428360600151116130fc57600061310c565b42836060015161310c9190614e6b565b9050600061311a4288614e6b565b9050818111613185576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f43616e6e6f742073686f7274656e206c6f636b2074696d6500000000000000006044820152606401610e41565b600f548110156131f1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f4d696e696d756d207374616b652074696d65206e6f74206d65740000000000006044820152606401610e41565b600e5481111561325d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f547279696e6720746f206c6f636b20666f7220746f6f206c6f6e6700000000006044820152606401610e41565b6040518060a001604052808981526020014281526020018560400151815260200188815260200161328d83610e91565b90523360009081526027602052604090208054859081106132b0576132b0614e3c565b906000526020600020906005020160008201518160000155602082015181600101556040820151816002015560608201518160030155608082015181600401559050506132fe3360006142fa565b6040805189815260208101839052428183015260608101899052905133917fc2cf1aae6decacbc52f96b4e4fec96d4ebab5236e4ed987165537bc463014a43919081900360800190a250506001600255505050505050565b73ffffffffffffffffffffffffffffffffffffffff8116600090815260246020526040812054610eb790670de0b6b3a764000090610d0b9061172e611a77565b60005473ffffffffffffffffffffffffffffffffffffffff163314806133d3575060095473ffffffffffffffffffffffffffffffffffffffff1633145b613439576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b00000000000000000000006044820152606401610e41565b602a80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff81166101009182900460ff1615909102179055565b602a5460ff1615156001146134e4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f4e6f7420696e206d6967726174696f6e000000000000000000000000000000006044820152606401610e41565b73ffffffffffffffffffffffffffffffffffffffff8216600090815260296020908152604080832033845290915290205460ff16801561353357503360009081526028602052604090205460ff165b613599576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f4d69672e20696e76616c6964206f7220756e617070726f7665640000000000006044820152606401610e41565b6135a4823383614006565b5050565b73ffffffffffffffffffffffffffffffffffffffff811660009081526028602052604090205460ff16613637576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f496e76616c6964206d69677261746f72206164647265737300000000000000006044820152606401610e41565b33600090815260296020908152604080832073ffffffffffffffffffffffffffffffffffffffff9490941683529290522080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b602a5465010000000000900460ff16613708576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f436f6e7472616374206e6f7420696e697469616c697a656400000000000000006044820152606401610e41565b61371061478b565b42600c8190556015546137239190613728565b600b55565b6000806137358385614e7e565b9050838110156137a1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f7700000000006044820152606401610e41565b9392505050565b60006137a183836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250614abc565b6000826000036137fc57506000610eb7565b60006138088385614dae565b9050826138158583614dc5565b146137a1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602160248201527f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f60448201527f77000000000000000000000000000000000000000000000000000000000000006064820152608401610e41565b60006137a183836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250614b10565b60008183106138f357816137a1565b5090919050565b84600161390782826142fa565b602a54640100000000900460ff16158061393557503360009081526028602052604090205460ff1615156001145b61399b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f5374616b696e6720706175736564206f7220696e206d6967726174696f6e00006044820152606401610e41565b60008511613a05576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f4d757374207374616b65206d6f7265207468616e207a65726f000000000000006044820152606401610e41565b600f54841015613a71576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f4d696e696d756d207374616b652074696d65206e6f74206d65740000000000006044820152606401610e41565b600e54841115613add576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f547279696e6720746f206c6f636b20666f7220746f6f206c6f6e6700000000006044820152606401610e41565b6000613ae885610e91565b73ffffffffffffffffffffffffffffffffffffffff891660009081526024602090815260408083205490517fffffffffffffffffffffffffffffffffffffffff00000000000000000000000060608e901b169281019290925260348201889052605482018a9052607482015291925090609401604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152828252805160209182012073ffffffffffffffffffffffffffffffffffffffff8d1660009081526027835283902060a0850184528185529184018990529183018a90529092509060608101613bdb888a613728565b8152602090810185905282546001818101855560009485529382902083516005909202019081559082015192810192909255604081015160028301556060810151600383015560800151600490910155600654613c509073ffffffffffffffffffffffffffffffffffffffff1689308a6145e2565b602254613c5d9088613728565b60225573ffffffffffffffffffffffffffffffffffffffff8916600090815260246020526040902054613c909088613728565b73ffffffffffffffffffffffffffffffffffffffff8a16600090815260246020526040812091909155613cc4908a906142fa565b604080518881526020810188905290810182905273ffffffffffffffffffffffffffffffffffffffff89811660608301528a16907ff400e72e69ef4402819dfc57eeddc66f5eb69bf405e0e8098b1946ec1ac14a229060800160405180910390a2505050505050505050565b600080836001613d4082826142fa565b73ffffffffffffffffffffffffffffffffffffffff86166000908152601e6020908152604080832054601f9092529091205490945092508315613ea85773ffffffffffffffffffffffffffffffffffffffff8681166000908152601e6020526040808220919091556004805491517fa9059cbb000000000000000000000000000000000000000000000000000000008152888416918101919091526024810187905291169063a9059cbb906044016020604051808303816000875af1158015613e0d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613e319190614e91565b508360186000828254613e449190614e7e565b90915550506004546040805186815273ffffffffffffffffffffffffffffffffffffffff9283166020820152878316818301529051918816917f1d2f2ca53af5d2f333bd32fdd45f9c52ad8ebe31414f7792912077fcb3876dff9181900360600190a25b8215613fd65773ffffffffffffffffffffffffffffffffffffffff8681166000908152601f60205260408082209190915560055490517fa9059cbb00000000000000000000000000000000000000000000000000000000815287831660048201526024810186905291169063a9059cbb906044016020604051808303816000875af1158015613f3b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613f5f9190614e91565b508260196000828254613f729190614e7e565b90915550506005546040805185815273ffffffffffffffffffffffffffffffffffffffff9283166020820152878316818301529051918816917f1d2f2ca53af5d2f333bd32fdd45f9c52ad8ebe31414f7792912077fcb3876dff9181900360600190a25b505073ffffffffffffffffffffffffffffffffffffffff9093166000908152602160205260409020429055929050565b6140108383613d30565b505060008061401f858461441d565b81519193509150831461408e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f5374616b65206e6f7420666f756e6400000000000000000000000000000000006044820152606401610e41565b8160600151421015806140ae5750602a5460ff6101009091041615156001145b806140cd57503360009081526028602052604090205460ff1615156001145b614133576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f5374616b65206973207374696c6c206c6f636b656421000000000000000000006044820152606401610e41565b604082015180156142f25760225461414b90826137a8565b60225573ffffffffffffffffffffffffffffffffffffffff861660009081526024602052604090205461417e90826137a8565b73ffffffffffffffffffffffffffffffffffffffff871660009081526024602090815260408083209390935560279052208054839081106141c1576141c1614e3c565b6000918252602082206005909102018181556001810182905560028101829055600381018290556004018190556141f99087906142fa565b6006546040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8781166004830152602482018490529091169063a9059cbb906044016020604051808303816000875af1158015614272573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906142969190614e91565b50604080518281526020810186905273ffffffffffffffffffffffffffffffffffffffff878116828401529151918816917f1d9308f6b22a2754a1c622bb30889e8f8f956c83e524d039e9d65d5f052eb9089181900360600190a25b505050505050565b801561430857614308613693565b73ffffffffffffffffffffffffffffffffffffffff8216156135a457600080600061433285612559565b92509250925061434185614b58565b73ffffffffffffffffffffffffffffffffffffffff851660009081526012602052604090208290558281106143c557600061437c82856137a8565b60235490915061438c9082613728565b6023556143998482613728565b73ffffffffffffffffffffffffffffffffffffffff871660009081526025602052604090205550614416565b60006143d184836137a8565b6023549091506143e190826137a8565b6023556143ee84826137a8565b73ffffffffffffffffffffffffffffffffffffffff8716600090815260256020526040902055505b5050505050565b6144526040518060a0016040528060008019168152602001600081526020016000815260200160008152602001600081525090565b6000805b73ffffffffffffffffffffffffffffffffffffffff85166000908152602760205260409020548110156145705773ffffffffffffffffffffffffffffffffffffffff851660009081526027602052604090208054829081106144ba576144ba614e3c565b906000526020600020906005020160000154840361455e5773ffffffffffffffffffffffffffffffffffffffff8516600090815260276020526040902080548290811061450957614509614e3c565b90600052602060002090600502016040518060a0016040529081600082015481526020016001820154815260200160028201548152602001600382015481526020016004820154815250509250809150614570565b8061456881614eb3565b915050614456565b50815183146145db576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f5374616b65206e6f7420666f756e6400000000000000000000000000000000006044820152606401610e41565b9250929050565b6040805173ffffffffffffffffffffffffffffffffffffffff85811660248301528481166044830152606480830185905283518084039091018152608490920183526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f23b872dd0000000000000000000000000000000000000000000000000000000017905291516000928392908816916146819190614f0f565b6000604051808303816000865af19150503d80600081146146be576040519150601f19603f3d011682016040523d82523d6000602084013e6146c3565b606091505b50915091508180156146ed5750805115806146ed5750808060200190518101906146ed9190614e91565b6142f2576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f5472616e7366657248656c7065723a205452414e534645525f46524f4d5f464160448201527f494c4544000000000000000000000000000000000000000000000000000000006064820152608401610e41565b600061478642600b546138e4565b905090565b60075473ffffffffffffffffffffffffffffffffffffffff16158015906147c157506015546020546147be9042906137a8565b10155b1561485f57600760009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16638f73c5ae6040518163ffffffff1660e01b81526004016020604051808303816000875af1158015614835573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906148599190614e00565b50426020555b600480546040517f70a08231000000000000000000000000000000000000000000000000000000008152309281019290925260009173ffffffffffffffffffffffffffffffffffffffff909116906370a0823190602401602060405180830381865afa1580156148d3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906148f79190614e00565b6005546040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015291925060009173ffffffffffffffffffffffffffffffffffffffff909116906370a0823190602401602060405180830381865afa15801561496b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061498f9190614e00565b905060006149b36149ab600c54426137a890919063ffffffff16565b6015546138e4565b6013549091506149c390826137ea565b601660008282546149d49190614e7e565b90915550506014546149e690826137ea565b601760008282546149f79190614e7e565b9250508190555050600080614a0a612e85565b601a91909155601b555050601854601654600091614a2891906137a8565b90506000614a436019546017546137a890919063ffffffff16565b9050818411614a56576000601355614a7e565b6000614a6285846137a8565b9050614a79601554826138a290919063ffffffff16565b601355505b808311614a8f57600060145561164a565b6000614a9b84836137a8565b9050614ab2601554826138a290919063ffffffff16565b6014555050505050565b60008184841115614afa576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610e419190614f2b565b506000614b078486614e6b565b95945050505050565b60008183614b4b576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610e419190614f2b565b506000614b078486614dc5565b73ffffffffffffffffffffffffffffffffffffffff811615614bd257600080614b8083610c3f565b73ffffffffffffffffffffffffffffffffffffffff85166000908152601e6020908152604080832094909455601f815283822092909255601a54601c835283822055601b54601d909252919091205550505b50565b803573ffffffffffffffffffffffffffffffffffffffff8116811461178357600080fd5b600060208284031215614c0b57600080fd5b6137a182614bd5565b600060208284031215614c2657600080fd5b5035919050565b60008060408385031215614c4057600080fd5b50508035926020909101359150565b602080825282518282018190526000919060409081850190868401855b82811015614cb05781518051855286810151878601528581015186860152606080820151908601526080908101519085015260a09093019290850190600101614c6c565b5091979650505050505050565b60008060008060808587031215614cd357600080fd5b614cdc85614bd5565b966020860135965060408601359560600135945092505050565b600080600060608486031215614d0b57600080fd5b505081359360208301359350604090920135919050565b60008060408385031215614d3557600080fd5b614d3e83614bd5565b946020939093013593505050565b60008060408385031215614d5f57600080fd5b614d6883614bd5565b9150614d7660208401614bd5565b90509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b8082028115828204841417610eb757610eb7614d7f565b600082614dfb577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b600060208284031215614e1257600080fd5b5051919050565b600060208284031215614e2b57600080fd5b815160ff811681146137a157600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b81810381811115610eb757610eb7614d7f565b80820180821115610eb757610eb7614d7f565b600060208284031215614ea357600080fd5b815180151581146137a157600080fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203614ee457614ee4614d7f565b5060010190565b60005b83811015614f06578181015183820152602001614eee565b50506000910152565b60008251614f21818460208701614eeb565b9190910192915050565b6020815260008251806020840152614f4a816040850160208701614eeb565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016919091016040019291505056fea26469706673582212208e51b29d8d870a62977c02553a5484997e40b9298e16fde38690de78adbaffc664736f6c63430008110033000000000000000000000000bca9a9aab13a68d311160d4f997e3d783da865fb0000000000000000000000009d2f299715d94d8a7e6f5eaa8e654e8c74a988a700000000000000000000000075c9bc761d88f70156daf83aa010e84680baf131000000000000000000000000147d0af556c6d89640bfa915d2b9619d7b55947a00000000000000000000000017fc002b466eec40dae837fc4be5c67993ddbd6f000000000000000000000000e61d9ed1e5dc261d1e90a99304fadcef2c76fd100000000000000000000000000000000000000000000000000000000000000000
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000bca9a9aab13a68d311160d4f997e3d783da865fb0000000000000000000000009d2f299715d94d8a7e6f5eaa8e654e8c74a988a700000000000000000000000075c9bc761d88f70156daf83aa010e84680baf131000000000000000000000000147d0af556c6d89640bfa915d2b9619d7b55947a00000000000000000000000017fc002b466eec40dae837fc4be5c67993ddbd6f000000000000000000000000e61d9ed1e5dc261d1e90a99304fadcef2c76fd100000000000000000000000000000000000000000000000000000000000000000
-----Decoded View---------------
Arg [0] : _owner (address): 0xbca9a9aab13a68d311160d4f997e3d783da865fb
Arg [1] : _rewardsToken0 (address): 0x9d2f299715d94d8a7e6f5eaa8e654e8c74a988a7
Arg [2] : _rewardsToken1 (address): 0x75c9bc761d88f70156daf83aa010e84680baf131
Arg [3] : _stakingToken (address): 0x147d0af556c6d89640bfa915d2b9619d7b55947a
Arg [4] : _frax_address (address): 0x17fc002b466eec40dae837fc4be5c67993ddbd6f
Arg [5] : _timelock_address (address): 0xe61d9ed1e5dc261d1e90a99304fadcef2c76fd10
Arg [6] : _rewarder_address (address): 0x0000000000000000000000000000000000000000
-----Encoded View---------------
7 Constructor Arguments found :
Arg [0] : 000000000000000000000000bca9a9aab13a68d311160d4f997e3d783da865fb
Arg [1] : 0000000000000000000000009d2f299715d94d8a7e6f5eaa8e654e8c74a988a7
Arg [2] : 00000000000000000000000075c9bc761d88f70156daf83aa010e84680baf131
Arg [3] : 000000000000000000000000147d0af556c6d89640bfa915d2b9619d7b55947a
Arg [4] : 00000000000000000000000017fc002b466eec40dae837fc4be5c67993ddbd6f
Arg [5] : 000000000000000000000000e61d9ed1e5dc261d1e90a99304fadcef2c76fd10
Arg [6] : 0000000000000000000000000000000000000000000000000000000000000000
Deployed ByteCode Sourcemap
128067:461:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;107909:541;;;;;;:::i;:::-;;:::i;:::-;;;;580:25:1;;;636:2;621:18;;614:34;;;;553:18;107909:541:0;;;;;;;;126912:113;;;;;;:::i;:::-;;:::i;:::-;;90875:27;;;;;;;;;;;;835:42:1;823:55;;;805:74;;793:2;778:18;90875:27:0;659:226:1;97246:477:0;;;;;;:::i;:::-;;:::i;:::-;;;1221:25:1;;;1209:2;1194:18;97246:477:0;1075:177:1;92259:58:0;;;;;;:::i;:::-;;;;;;;;;;;;;;34432:141;;;;;;:::i;:::-;;:::i;122359:386::-;;;:::i;114499:163::-;;;;;;:::i;:::-;;:::i;90292:19::-;;;;;;;;;123782:261;;;;;;:::i;:::-;;:::i;108458:204::-;;;:::i;97105:133::-;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;122872:357::-;;;;;;:::i;:::-;;:::i;101459:1055::-;;;;;;:::i;:::-;;:::i;91853:26::-;;;;;;93553:35;;;;;;;;;;;;;;;3333:14:1;;3326:22;3308:41;;3296:2;3281:18;93553:35:0;3168:187:1;96920:127:0;;;;;;:::i;:::-;97013:26;;96986:7;97013:26;;;:17;:26;;;;;;;96920:127;91943:39;;;;;;93665:25;;;;;;;;;;;;126292:96;;;:::i;118477:210::-;;;:::i;101264:187::-;;;;;;:::i;:::-;;:::i;116538:194::-;;;;;;:::i;:::-;;:::i;114183:183::-;;;;;;:::i;:::-;114329:10;114304:36;;;;:24;:36;;;;;;;;;:54;;;;;;;;;;114297:61;;;;;;114183:183;34200:29;;;;;;;;;97872:3219;;;:::i;92072:26::-;;;;;;96754:111;96835:22;;96754:111;;91109:33;;;;;;;;;92439:43;;;;;;:::i;:::-;;;;;;;;;;;;;;124733:796;;;;;;:::i;:::-;;:::i;92489:29::-;;;;;;91460:36;;;;;;90645:34;;;;;;;;;102522:2692;;;;;;:::i;:::-;;:::i;92944:53::-;;;;;;:::i;:::-;;:::i;:::-;;;;4638:25:1;;;4694:2;4679:18;;4672:34;;;;4722:18;;;4715:34;;;;4780:2;4765:18;;4758:34;4823:3;4808:19;;4801:35;4625:3;4610:19;92944:53:0;4379:463:1;34581:271:0;;;:::i;126512:126::-;;;:::i;90392:26::-;;;;;;;;;124172:553;;;;;;:::i;:::-;;:::i;105275:1952::-;;;;;;:::i;:::-;;:::i;:::-;;;;5294:25:1;;;5350:2;5335:18;;5328:34;;;;5378:18;;;5371:34;5282:2;5267:18;105275:1952:0;5092:319:1;34173:20:0;;;;;;;;;126771:133;;;;;;:::i;:::-;;:::i;93399:26::-;;;;;;;;;;;;93169:76;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;123612:128;;;;;;:::i;:::-;;:::i;91886:26::-;;;;;;126187:97;;;:::i;92105:26::-;;;;;;125537:537;;;;;;:::i;:::-;;:::i;110846:1145::-;;;;;;:::i;:::-;;:::i;91381:61::-;;;;;;93614:25;;;;;;;;;;;;126646:117;;;;;;:::i;:::-;;:::i;92039:26::-;;;;;;92389:43;;;;;;:::i;:::-;;;;;;;;;;;;;;90318;;;;;;;;;91227:29;;;;;;107235:666;;;:::i;91307:50::-;;;;;;126396:108;;;:::i;112045:1355::-;;;;;;:::i;:::-;;:::i;101099:157::-;;;;;;:::i;:::-;;:::i;96451:128::-;;;;;;:::i;:::-;96545:26;;96518:7;96545:26;;;:17;:26;;;;;;;96451:128;91040:31;;;;;;;;;90815:38;;;;;;;;;96285:113;96367:23;;96285:113;;126082:97;;;:::i;92138:26::-;;;;;;93498:29;;;;;;;;;;;;123265:298;;;;;;:::i;:::-;;:::i;91193:27::-;;;;;;93058:47;;;;;;:::i;:::-;;;;;;;;;;;;;;;;113889:226;;;;;;:::i;:::-;;:::i;91680:51::-;;;;;;91549:59;;;;;;93286:24;;;;;;;;;92324:58;;;;;;:::i;:::-;;;;;;;;;;;;;;121836:376;;;:::i;107909:541::-;107963:7;107972;107993:22;108017;108043:16;:14;:16::i;:::-;108074:26;;;;;;;:17;:26;;;;;;107992:67;;-1:-1:-1;107992:67:0;;-1:-1:-1;108074:31:0;108070:76;;-1:-1:-1;108129:1:0;;;;-1:-1:-1;107909:541:0;-1:-1:-1;;;107909:541:0:o;108070:76::-;108279:17;;;;;;;:8;:17;;;;;;;;;108229:23;:32;;;;;;;108178:119;;108279:17;108178:96;;108269:4;;108179:84;;108210:52;;:14;;:18;:52::i;:::-;108179:26;;;;;;;:17;:26;;;;;;;:30;:84::i;:::-;108178:90;;:96::i;:::-;:100;;:119::i;:::-;108413:17;;;;;;;:8;:17;;;;;;;;;108363:23;:32;;;;;;;108312:119;;108413:17;108312:96;;108403:4;;108313:84;;108344:52;;:14;;:18;:52::i;:::-;108313:26;;;;;;;:17;:26;;;;;;;:30;:84::i;108312:119::-;108156:286;;;;;;107909:541;;;:::o;126912:113::-;94080:5;;;;94066:10;:19;;:53;;-1:-1:-1;94103:16:0;;;;94089:10;:30;94066:53;94058:87;;;;;;;6919:2:1;94058:87:0;;;6901:21:1;6958:2;6938:18;;;6931:30;6997:23;6977:18;;;6970:51;7038:18;;94058:87:0;;;;;;;;;126987:5:::1;:30:::0;;;::::1;;::::0;;;::::1;::::0;;;::::1;::::0;;126912:113::o;97246:477::-;97610:19;;97675:28;;97305:7;;97587:127;;97645:26;97610:19;97645:4;:26;:::i;:::-;97644:59;;;;:::i;:::-;97587:8;:127::i;:::-;97580:134;97246:477;-1:-1:-1;;97246:477:0:o;34432:141::-;34912:5;;;;34898:10;:19;34890:79;;;;;;;7910:2:1;34890:79:0;;;7892:21:1;7949:2;7929:18;;;7922:30;7988:34;7968:18;;;7961:62;8059:17;8039:18;;;8032:45;8094:19;;34890:79:0;7708:411:1;34890:79:0;34504:14:::1;:23:::0;;;::::1;;::::0;::::1;::::0;;::::1;::::0;;;34543:22:::1;::::0;805:74:1;;;34543:22:0::1;::::0;793:2:1;778:18;34543:22:0::1;;;;;;;34432:141:::0;:::o;122359:386::-;94235:5;;;;94221:10;:19;;:53;;-1:-1:-1;94258:16:0;;;;94244:10;:30;94221:53;:89;;;-1:-1:-1;94292:18:0;;;;94278:10;:32;94221:89;94213:124;;;;;;;8326:2:1;94213:124:0;;;8308:21:1;8365:2;8345:18;;;8338:30;8404:24;8384:18;;;8377:52;8446:18;;94213:124:0;8124:346:1;94213:124:0;122435:13:::1;::::0;;;::::1;;;122434:14;122426:46;;;::::0;::::1;::::0;;8677:2:1;122426:46:0::1;::::0;::::1;8659:21:1::0;8716:2;8696:18;;;8689:30;8755:21;8735:18;;;8728:49;8794:18;;122426:46:0::1;8475:343:1::0;122426:46:0::1;122483:13;:20:::0;;;::::1;::::0;::::1;::::0;;122572:8:::1;::::0;122564:31:::1;122572:8;122564:31:::0;122560:137:::1;;122611:8;;;;;;;;;;;:25;;;:27;;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1::0;122670:15:0::1;122653:14;:32:::0;122560:137:::1;122714:23;::::0;::::1;::::0;;;::::1;122359:386::o:0;114499:163::-;38347:1;38953:7;;:19;38945:63;;;;;;;9214:2:1;38945:63:0;;;9196:21:1;9253:2;9233:18;;;9226:30;9292:33;9272:18;;;9265:61;9343:18;;38945:63:0;9012:355:1;38945:63:0;38347:1;39086:18;;114584:70:::1;114597:10;::::0;114621:9;114632:4;114638:15:::1;114584:12;:70::i;:::-;-1:-1:-1::0;;38303:1:0;39265:7;:22;114499:163::o;123782:261::-;94080:5;;;;94066:10;:19;;:53;;-1:-1:-1;94103:16:0;;;;94089:10;:30;94066:53;94058:87;;;;;;;6919:2:1;94058:87:0;;;6901:21:1;6958:2;6938:18;;;6931:30;6997:23;6977:18;;;6970:51;7038:18;;94058:87:0;6717:345:1;94058:87:0;123873:33:::1;::::0;::::1;;::::0;;;:15:::1;:33;::::0;;;;;::::1;;:41;;:33:::0;:41:::1;123865:73;;;::::0;::::1;::::0;;9574:2:1;123865:73:0::1;::::0;::::1;9556:21:1::0;9613:2;9593:18;;;9586:30;9652:21;9632:18;;;9625:49;9691:18;;123865:73:0::1;9372:343:1::0;123865:73:0::1;124002:33;;;::::0;;;:15:::1;:33;::::0;;;;123995:40;;;::::1;::::0;;123782:261::o;108458:204::-;108513:7;108522;108564:32;108580:15;;108564:11;;:15;;:32;;;;:::i;:::-;108627:15;;108611:11;;:32;;:15;:32::i;:::-;108542:112;;;;108458:204;;:::o;97105:133::-;97209:21;;;;;;;:12;:21;;;;;;;;97202:28;;;;;;;;;;;;;;;;;97169:20;;97202:28;;97209:21;;97202:28;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;97105:133;;;:::o;122872:357::-;94407:12;;;;:20;;:12;:20;94399:49;;;;;;;9922:2:1;94399:49:0;;;9904:21:1;9961:2;9941:18;;;9934:30;10000:18;9980;;;9973:46;10036:18;;94399:49:0;9720:340:1;94399:49:0;123025:40:::1;::::0;::::1;;::::0;;;:24:::1;:40;::::0;;;;;;;123066:10:::1;123025:52:::0;;;;;;;;::::1;;:83:::0;::::1;;;-1:-1:-1::0;123097:10:0::1;123081:27;::::0;;;:15:::1;:27;::::0;;;;;::::1;;123025:83;123017:122;;;::::0;::::1;::::0;;10267:2:1;123017:122:0::1;::::0;::::1;10249:21:1::0;10306:2;10286:18;;;10279:30;10345:28;10325:18;;;10318:56;10391:18;;123017:122:0::1;10065:350:1::0;123017:122:0::1;123150:71;123163:14;123179:10;123191:6;123199:4;123205:15;123150:12;:71::i;:::-;122872:357:::0;;;;:::o;101459:1055::-;101554:5;;101522:7;;101546:28;101554:5;101546:28;101542:964;;101752:34;101789:28;101809:7;101789:19;:28::i;:::-;101752:65;-1:-1:-1;101836:30:0;;101832:570;;101918:5;;:24;;;;;:5;823:55:1;;;101918:24:0;;;805:74:1;101887:27:0;;101917:84;;101974:26;;101917:52;;91003:4;;101918:5;;;:15;;778:18:1;;101918:24:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;101917:30;;:52::i;:84::-;101887:114;;102038:24;102065:75;91003:4;102066:47;102092:20;;102067:19;102066:25;;:47;;;;:::i;102065:75::-;102038:102;;102246:20;;102227:16;:39;102223:84;;;-1:-1:-1;102287:20:0;;102223:84;102335:16;101459:1055;-1:-1:-1;;;;101459:1055:0:o;101832:570::-;-1:-1:-1;102401:1:0;;101459:1055;-1:-1:-1;;101459:1055:0:o;101542:964::-;-1:-1:-1;102505:1:0;;101459:1055;-1:-1:-1;101459:1055:0:o;101542:964::-;101459:1055;;;:::o;126292:96::-;94080:5;;;;94066:10;:19;;:53;;-1:-1:-1;94103:16:0;;;;94089:10;:30;94066:53;94058:87;;;;;;;6919:2:1;94058:87:0;;;6901:21:1;6958:2;6938:18;;;6931:30;6997:23;6977:18;;;6970:51;7038:18;;94058:87:0;6717:345:1;94058:87:0;126367:13:::1;::::0;;126350:30;;::::1;126367:13:::0;;;;::::1;;;126366:14;126350:30:::0;;::::1;;::::0;;126292:96::o;118477:210::-;118529:7;118538;38347:1;38953:7;;:19;38945:63;;;;;;;9214:2:1;38945:63:0;;;9196:21:1;9253:2;9233:18;;;9226:30;9292:33;9272:18;;;9265:61;9343:18;;38945:63:0;9012:355:1;38945:63:0;38347:1;39086:18;;118566:23:::1;::::0;;;::::1;;;:32;118558:69;;;::::0;::::1;::::0;;10622:2:1;118558:69:0::1;::::0;::::1;10604:21:1::0;10661:2;10641:18;;;10634:30;10700:27;10680:18;;;10673:55;10745:18;;118558:69:0::1;10420:349:1::0;118558:69:0::1;118645:34;118656:10;118668;118645;:34::i;:::-;118638:41;;;;38303:1:::0;39265:7;:22;118477:210;;:::o;101264:187::-;101331:7;101358:85;91003:4;101358:59;101388:28;;101359:23;101374:7;101359:14;:23::i;116538:194::-;38347:1;38953:7;;:19;38945:63;;;;;;;9214:2:1;38945:63:0;;;9196:21:1;9253:2;9233:18;;;9226:30;9292:33;9272:18;;;9265:61;9343:18;;38945:63:0;9012:355:1;38945:63:0;38347:1;39086:18;;116617:17:::1;::::0;;;::::1;;;:26;116609:57;;;::::0;::::1;::::0;;10976:2:1;116609:57:0::1;::::0;::::1;10958:21:1::0;11015:2;10995:18;;;10988:30;11054:20;11034:18;;;11027:48;11092:18;;116609:57:0::1;10774:342:1::0;116609:57:0::1;116677:47;116693:10;116705;116717:6;116677:15;:47::i;:::-;-1:-1:-1::0;38303:1:0;39265:7;:22;116538:194::o;97872:3219::-;100045:12;;100026:32;;;;;100005:20;100045:12;;;100026:32;;;805:74:1;97919:7:0;;;;99926:42;;97919:7;;99926:42;;100005:20;;99926:42;;100026:18;;778::1;;100026:32:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;100005:54;;;;;;;;;;11571:4:1;11559:17;;;100005:54:0;;;11541:36:1;11514:18;;100005:54:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;99984:75;;100094:52;100119:12;;;;;;;;;;;:24;;;:26;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;100094:20;:10;100109:4;100094:14;:20::i;124733:796::-;94080:5;;;;94066:10;:19;;:53;;-1:-1:-1;94103:16:0;;;;94089:10;:30;94066:53;94058:87;;;;;;;6919:2:1;94058:87:0;;;6901:21:1;6958:2;6938:18;;;6931:30;6997:23;6977:18;;;6970:51;7038:18;;94058:87:0;6717:345:1;94058:87:0;91003:4:::1;124898:20;:44;;124890:93;;;::::0;::::1;::::0;;11790:2:1;124890:93:0::1;::::0;::::1;11772:21:1::0;11829:2;11809:18;;;11802:30;11868:34;11848:18;;;11841:62;11939:6;11919:18;;;11912:34;11963:19;;124890:93:0::1;11588:400:1::0;124890:93:0::1;125106:1;125074:29;:33;125066:72;;;::::0;::::1;::::0;;12546:2:1;125066:72:0::1;::::0;::::1;12528:21:1::0;12585:2;12565:18;;;12558:30;12624:28;12604:18;;;12597:56;12670:18;;125066:72:0::1;12344:350:1::0;125066:72:0::1;125151:19;:42:::0;;;125204:20:::1;:44:::0;;;125259:28:::1;:60:::0;;;125337:40:::1;::::0;1221:25:1;;;125337:40:0::1;::::0;1209:2:1;1194:18;125337:40:0::1;;;;;;;125393:52;125425:19;;125393:52;;;;1221:25:1::0;;1209:2;1194:18;;1075:177;125393:52:0::1;;;;;;;;125461:60;125492:28;;125461:60;;;;1221:25:1::0;;1209:2;1194:18;;1075:177;125461:60:0::1;;;;;;;;124733:796:::0;;;:::o;102522:2692::-;102713:21;;;102611:32;102713:21;;;:12;:21;;;;;:32;;102611;;102713:21;102735:9;;102713:32;;;;;;:::i;:::-;;;;;;;;;102682:63;;;;;;;;102713:32;;;;;;;102682:63;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;102928:28;;;;;:19;:28;;;;;;102682:63;;-1:-1:-1;;102924:224:0;;;-1:-1:-1;103021:25:0;;;;102924:224;;;-1:-1:-1;103108:28:0;;;;;;;:19;:28;;;;;;102924:224;103237:15;103207:9;:26;;;:45;103203:1802;;103432:26;;;;103401:28;;;;;;;:19;:28;;;;;;:57;103397:1087;;;103478:26;103536:17;103507:9;:26;;;:46;;;;:::i;:::-;103478:75;;103572:25;103618:9;:26;;;103600:15;:44;;;;:::i;:::-;103572:72;-1:-1:-1;103724:33:0;103760:38;103775:22;103796:1;103775:18;:22;:::i;103760:38::-;103724:74;-1:-1:-1;104015:17:0;104087:21;104091:17;104015;104087:21;:::i;:::-;104036:46;104064:18;104036:25;:46;:::i;:::-;104035:74;;;;:::i;:::-;104015:94;-1:-1:-1;104168:38:0;104189:17;104168:18;:38;:::i;:::-;104155:52;;:9;:52;:::i;:::-;104128:79;;103459:764;;;;103203:1802;;103397:1087;104467:1;104440:28;;103203:1802;;;104629:21;104684:20;104736:17;104707:9;:26;;;:46;;;;:::i;:::-;104684:69;;104772:20;104824:15;104795:9;:26;;;:44;;;;:::i;:::-;104772:67;-1:-1:-1;104906:1:0;104875:27;104772:67;104875:12;:27;:::i;:::-;104874:33;;;;:::i;:::-;104858:49;;104665:258;;104964:29;104979:13;104964:14;:29::i;:::-;104937:56;;104549:456;103203:1802;105127:9;:25;;;105100:24;:52;105096:110;;;105181:9;:25;;;105154:52;;105096:110;102645:2569;;102522:2692;;;;:::o;92944:53::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;92944:53:0;;-1:-1:-1;92944:53:0;;;:::o;34581:271::-;34650:14;;;;34636:10;:28;34628:94;;;;;;;13353:2:1;34628:94:0;;;13335:21:1;13392:2;13372:18;;;13365:30;13431:34;13411:18;;;13404:62;13502:23;13482:18;;;13475:51;13543:19;;34628:94:0;13151:417:1;34628:94:0;34751:5;;;34758:14;34738:35;;;34751:5;;;;13808:34:1;;34758:14:0;;;;13873:2:1;13858:18;;13851:43;34738:35:0;;13720:18:1;34738:35:0;;;;;;;34792:14;;;;34784:22;;;;;;34792:14;;;34784:22;;;;34817:27;;;34581:271::o;126512:126::-;94080:5;;;;94066:10;:19;;:53;;-1:-1:-1;94103:16:0;;;;94089:10;:30;94066:53;94058:87;;;;;;;6919:2:1;94058:87:0;;;6901:21:1;6958:2;6938:18;;;6931:30;6997:23;6977:18;;;6970:51;7038:18;;94058:87:0;6717:345:1;94058:87:0;126607:23:::1;::::0;;126580:50;;::::1;126607:23:::0;;;;::::1;;;126606:24;126580:50:::0;;::::1;;::::0;;126512:126::o;124172:553::-;94080:5;;;;94066:10;:19;;:53;;-1:-1:-1;94103:16:0;;;;94089:10;:30;94066:53;94058:87;;;;;;;6919:2:1;94058:87:0;;;6901:21:1;6958:2;6938:18;;;6931:30;6997:23;6977:18;;;6970:51;7038:18;;94058:87:0;6717:345:1;94058:87:0;124371:12:::1;::::0;::::1;;124367:164;;124431:12;::::0;::::1;::::0;;::::1;124407:37:::0;;::::1;::::0;124399:66:::1;;;::::0;::::1;::::0;;9922:2:1;124399:66:0::1;::::0;::::1;9904:21:1::0;9961:2;9941:18;;;9934:30;10000:18;9980;;;9973:46;10036:18;;124399:66:0::1;9720:340:1::0;124399:66:0::1;124646:5;::::0;124617:48:::1;::::0;;;;:28:::1;124646:5:::0;;::::1;124617:48;::::0;::::1;14079:74:1::0;14169:18;;;14162:34;;;124617:28:0;;::::1;::::0;::::1;::::0;14052:18:1;;124617:48:0::1;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1::0;124681:36:0::1;::::0;;14109:42:1;14097:55;;14079:74;;14184:2;14169:18;;14162:34;;;124681:36:0::1;::::0;14052:18:1;124681:36:0::1;;;;;;;;124172:553:::0;;:::o;105275:1952::-;105569:26;;;105367:27;105569:26;;;:17;:26;;;;;;;105367:27;105756:24;105587:7;105756:15;:24::i;:::-;105856:26;;;105793:33;105856:26;;;:17;:26;;;;;;105733:47;;-1:-1:-1;105793:33:0;105856:31;:66;;;;-1:-1:-1;105891:26:0;;;;;;;:17;:26;;;;;;:31;105856:66;105855:143;;;-1:-1:-1;105966:31:0;;;;;;;:22;:31;;;;;;105942:55;;;105855:143;105837:638;;;-1:-1:-1;106239:20:0;105837:638;;;106427:31;;;;;;;:22;:31;;;;;;106462:1;;106404:54;;:20;:54;:::i;:::-;106403:60;;;;:::i;:::-;106375:88;;105837:638;106610:1;106588:23;;106627:9;106622:598;106646:21;;;;;;;:12;:21;;;;;:28;106642:32;;106622:598;;;106727:21;;;106696:28;106727:21;;;:12;:21;;;;;:24;;106749:1;;106727:24;;;;;;:::i;:::-;;;;;;;;;;;106696:55;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;106823:32;106858:34;106881:7;106890:1;106858:22;:34::i;:::-;106974:19;;;;106823:69;;-1:-1:-1;106954:17:0;91003:4;107069:52;107096:25;106823:69;107069:52;:::i;:::-;107056:66;;:9;:66;:::i;:::-;107055:91;;;;:::i;:::-;107042:105;;:9;:105;:::i;:::-;107008:139;-1:-1:-1;107162:46:0;107008:139;107162:46;;:::i;:::-;;;106681:539;;;;106676:3;;;;;:::i;:::-;;;;106622:598;;;;105496:1731;105275:1952;;;;;:::o;126771:133::-;94080:5;;;;94066:10;:19;;:53;;-1:-1:-1;94103:16:0;;;;94089:10;:30;94066:53;94058:87;;;;;;;6919:2:1;94058:87:0;;;6901:21:1;6958:2;6938:18;;;6931:30;6997:23;6977:18;;;6970:51;7038:18;;94058:87:0;6717:345:1;94058:87:0;126856:18:::1;:40:::0;;;::::1;;::::0;;;::::1;::::0;;;::::1;::::0;;126771:133::o;123612:128::-;94080:5;;;;94066:10;:19;;:53;;-1:-1:-1;94103:16:0;;;;94089:10;:30;94066:53;94058:87;;;;;;;6919:2:1;94058:87:0;;;6901:21:1;6958:2;6938:18;;;6931:30;6997:23;6977:18;;;6970:51;7038:18;;94058:87:0;6717:345:1;94058:87:0;123692:33:::1;;;::::0;;;:15:::1;:33;::::0;;;;:40;;;::::1;123728:4;123692:40;::::0;;123612:128::o;126187:97::-;94080:5;;;;94066:10;:19;;:53;;-1:-1:-1;94103:16:0;;;;94089:10;:30;94066:53;94058:87;;;;;;;6919:2:1;94058:87:0;;;6901:21:1;6958:2;6938:18;;;6931:30;6997:23;6977:18;;;6970:51;7038:18;;94058:87:0;6717:345:1;94058:87:0;126264:12:::1;::::0;;126248:28;;::::1;126264:12;::::0;;::::1;126263:13;126248:28;::::0;;126187:97::o;125537:537::-;94080:5;;;;94066:10;:19;;:53;;-1:-1:-1;94103:16:0;;;;94089:10;:30;94066:53;94058:87;;;;;;;6919:2:1;94058:87:0;;;6901:21:1;6958:2;6938:18;;;6931:30;6997:23;6977:18;;;6970:51;7038:18;;94058:87:0;6717:345:1;94058:87:0;125724:1:::1;125691:29;:34;;125683:72;;;::::0;::::1;::::0;;14891:2:1;125683:72:0::1;::::0;::::1;14873:21:1::0;14930:2;14910:18;;;14903:30;14969:27;14949:18;;;14942:55;15014:18;;125683:72:0::1;14689:349:1::0;125683:72:0::1;125792:1;125774:14;:19;;125766:57;;;::::0;::::1;::::0;;15245:2:1;125766:57:0::1;::::0;::::1;15227:21:1::0;15284:2;15264:18;;;15257:30;15323:27;15303:18;;;15296:55;15368:18;;125766:57:0::1;15043:349:1::0;125766:57:0::1;125836:28;:60:::0;;;125907:13:::1;:30:::0;;;125955:61:::1;::::0;1221:25:1;;;125955:61:0::1;::::0;1209:2:1;1194:18;125955:61:0::1;;;;;;;126032:34;::::0;1221:25:1;;;126032:34:0::1;::::0;1209:2:1;1194:18;126032:34:0::1;1075:177:1::0;110846:1145:0;110927:10;110939:4;94667:42;94691:7;94700:8;94667:23;:42::i;:::-;111004:28:::1;111034:21:::0;111059:29:::1;111069:10;111081:6;111059:9;:29::i;:::-;111003:85;;;;111138:15;111178:8;111156:9;:19;;;:30;;;;:::i;:::-;111138:48:::0;-1:-1:-1;111356:12:0::1;::::0;111316:91:::1;::::0;111356:12:::1;;111371:10;111391:4;111398:8:::0;111316:31:::1;:91::i;:::-;111491:186;::::0;;::::1;::::0;::::1;::::0;;;;;::::1;111538:25:::0;;::::1;::::0;111491:186;;::::1;::::0;;;;;;;;111600:26;;::::1;::::0;111491:186;;;;;111641:25;;::::1;::::0;111491:186;;;;111462:10:::1;-1:-1:-1::0;111449:24:0;;;:12:::1;:24:::0;;;;;;;:39;;111474:13;;111449:39;::::1;;;;;:::i;:::-;;;;;;;;;;;:228;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;111748:8;111721:23;;:35;;;;;;;:::i;:::-;::::0;;;-1:-1:-1;;111785:10:0::1;111767:29;::::0;;;:17:::1;:29;::::0;;;;:41;;111800:8;;111767:29;:41:::1;::::0;111800:8;;111767:41:::1;:::i;:::-;::::0;;;-1:-1:-1;111877:42:0::1;::::0;-1:-1:-1;111901:10:0::1;111913:5;111877:23;:42::i;:::-;111937:46;::::0;;580:25:1;;;636:2;621:18;;614:34;;;111954:10:0::1;::::0;111937:46:::1;::::0;553:18:1;111937:46:0::1;;;;;;;110952:1039;;;110846:1145:::0;;;;:::o;126646:117::-;94080:5;;;;94066:10;:19;;:53;;-1:-1:-1;94103:16:0;;;;94089:10;:30;94066:53;94058:87;;;;;;;6919:2:1;94058:87:0;;;6901:21:1;6958:2;6938:18;;;6931:30;6997:23;6977:18;;;6970:51;7038:18;;94058:87:0;6717:345:1;94058:87:0;126723:16:::1;:32:::0;;;::::1;;::::0;;;::::1;::::0;;;::::1;::::0;;126646:117::o;107235:666::-;107282:7;107291;107315:23;;107342:1;107315:28;:59;;;-1:-1:-1;107347:22:0;;:27;107315:59;107311:583;;;-1:-1:-1;;107399:21:0;;107422;;107399;;107235:666::o;107311:583::-;107512:168;107560:101;107638:22;;107560:73;107628:4;107560:63;107611:11;;107560:46;107591:14;;107560:26;:24;:26::i;:::-;:30;;:46::i;:101::-;107512:21;;;:25;:168::i;:::-;107699;107747:101;107825:22;;107747:73;107815:4;107747:63;107798:11;;107747:46;107778:14;;107747:26;:24;:26::i;:101::-;107699:21;;;:25;:168::i;126396:108::-;94080:5;;;;94066:10;:19;;:53;;-1:-1:-1;94103:16:0;;;;94089:10;:30;94066:53;94058:87;;;;;;;6919:2:1;94058:87:0;;;6901:21:1;6958:2;6938:18;;;6931:30;6997:23;6977:18;;;6970:51;7038:18;;94058:87:0;6717:345:1;94058:87:0;126479:17:::1;::::0;;126458:38;;::::1;126479:17:::0;;;;::::1;;;126478:18;126458:38:::0;;::::1;;::::0;;126396:108::o;112045:1355::-;38347:1;38953:7;;:19;38945:63;;;;;;;9214:2:1;38945:63:0;;;9196:21:1;9253:2;9233:18;;;9226:30;9292:33;9272:18;;;9265:61;9343:18;;38945:63:0;9012:355:1;38945:63:0;38347:1;39086:18;;112140:10:::1;112152:4;94667:42;112140:10:::0;112152:4;94667:23:::1;:42::i;:::-;112217:28:::2;112247:21:::0;112272:29:::2;112282:10;112294:6;112272:9;:29::i;:::-;112216:85;;;;112356:15;112340:13;:31;112332:65;;;::::0;::::2;::::0;;16196:2:1;112332:65:0::2;::::0;::::2;16178:21:1::0;16235:2;16215:18;;;16208:30;16274:23;16254:18;;;16247:51;16315:18;;112332:65:0::2;15994:345:1::0;112332:65:0::2;112443:17;112493:15;112464:9;:26;;;:44;112463:97;;112559:1;112463:97;;;112541:15;112512:9;:26;;;:44;;;;:::i;:::-;112443:117:::0;-1:-1:-1;112571:16:0::2;112590:31;112606:15;112590:13:::0;:31:::2;:::i;:::-;112571:50;;112727:9;112716:8;:20;112708:57;;;::::0;::::2;::::0;;16546:2:1;112708:57:0::2;::::0;::::2;16528:21:1::0;16585:2;16565:18;;;16558:30;16624:26;16604:18;;;16597:54;16668:18;;112708:57:0::2;16344:348:1::0;112708:57:0::2;112796:13;;112784:8;:25;;112776:64;;;::::0;::::2;::::0;;16899:2:1;112776:64:0::2;::::0;::::2;16881:21:1::0;16938:2;16918:18;;;16911:30;16977:28;16957:18;;;16950:56;17023:18;;112776:64:0::2;16697:350:1::0;112776:64:0::2;112871:28;;112859:8;:40;;112851:80;;;::::0;::::2;::::0;;17254:2:1;112851:80:0::2;::::0;::::2;17236:21:1::0;17293:2;17273:18;;;17266:30;17332:29;17312:18;;;17305:57;17379:18;;112851:80:0::2;17052:351:1::0;112851:80:0::2;113015:174;;;;;;;;113041:6;113015:174;;;;113062:15;113015:174;;;;113092:9;:19;;;113015:174;;;;113126:13;113015:174;;;;113154:24;113169:8;113154:14;:24::i;:::-;113015:174:::0;;112986:10:::2;112973:24;::::0;;;:12:::2;:24;::::0;;;;:39;;112998:13;;112973:39;::::2;;;;;:::i;:::-;;;;;;;;;;;:216;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;113258:42;113282:10;113294:5;113258:23;:42::i;:::-;113318:74;::::0;;17639:25:1;;;17695:2;17680:18;;17673:34;;;113361:15:0::2;17723:18:1::0;;;17716:34;17781:2;17766:18;;17759:34;;;113318:74:0;;113331:10:::2;::::0;113318:74:::2;::::0;;;;;17626:3:1;113318:74:0;;::::2;-1:-1:-1::0;;38303:1:0;39265:7;:22;-1:-1:-1;;;;;;112045:1355:0:o;101099:157::-;101211:26;;;101161:7;101211:26;;;:17;:26;;;;;;101188:60;;101243:4;;101188:50;;101189:16;:14;:16::i;126082:97::-;94080:5;;;;94066:10;:19;;:53;;-1:-1:-1;94103:16:0;;;;94089:10;:30;94066:53;94058:87;;;;;;;6919:2:1;94058:87:0;;;6901:21:1;6958:2;6938:18;;;6931:30;6997:23;6977:18;;;6970:51;7038:18;;94058:87:0;6717:345:1;94058:87:0;126157:14:::1;::::0;;126139:32;;::::1;126157:14;::::0;;;::::1;;;126156:15;126139:32:::0;;::::1;;::::0;;126082:97::o;123265:298::-;94407:12;;;;:20;;:12;:20;94399:49;;;;;;;9922:2:1;94399:49:0;;;9904:21:1;9961:2;9941:18;;;9934:30;10000:18;9980;;;9973:46;10036:18;;94399:49:0;9720:340:1;94399:49:0;123379:40:::1;::::0;::::1;;::::0;;;:24:::1;:40;::::0;;;;;;;123420:10:::1;123379:52:::0;;;;;;;;::::1;;:83:::0;::::1;;;-1:-1:-1::0;123451:10:0::1;123435:27;::::0;;;:15:::1;:27;::::0;;;;;::::1;;123379:83;123371:122;;;::::0;::::1;::::0;;10267:2:1;123371:122:0::1;::::0;::::1;10249:21:1::0;10306:2;10286:18;;;10279:30;10345:28;10325:18;;;10318:56;10391:18;;123371:122:0::1;10065:350:1::0;123371:122:0::1;123504:51;123520:14;123536:10;123548:6;123504:15;:51::i;:::-;123265:298:::0;;:::o;113889:226::-;113972:33;;;;;;;:15;:33;;;;;;;;113964:70;;;;;;;18006:2:1;113964:70:0;;;17988:21:1;18045:2;18025:18;;;18018:30;18084:26;18064:18;;;18057:54;18128:18;;113964:70:0;17804:348:1;113964:70:0;114070:10;114045:36;;;;:24;:36;;;;;;;;;:54;;;;;;;;;;:61;;;;114102:4;114045:61;;;113889:226::o;121836:376::-;121878:13;;;;;;;121870:50;;;;;;;18359:2:1;121870:50:0;;;18341:21:1;18398:2;18378:18;;;18371:30;18437:26;18417:18;;;18410:54;18481:18;;121870:50:0;18157:348:1;121870:50:0;122040:13;:11;:13::i;:::-;122125:15;122108:14;:32;;;122188:15;;122166:38;;122125:15;122166:21;:38::i;:::-;122151:12;:53;121836:376::o;1962:181::-;2020:7;;2052:5;2056:1;2052;:5;:::i;:::-;2040:17;;2081:1;2076;:6;;2068:46;;;;;;;18712:2:1;2068:46:0;;;18694:21:1;18751:2;18731:18;;;18724:30;18790:29;18770:18;;;18763:57;18837:18;;2068:46:0;18510:351:1;2068:46:0;2134:1;1962:181;-1:-1:-1;;;1962:181:0:o;2418:136::-;2476:7;2503:43;2507:1;2510;2503:43;;;;;;;;;;;;;;;;;:3;:43::i;3334:471::-;3392:7;3637:1;3642;3637:6;3633:47;;-1:-1:-1;3667:1:0;3660:8;;3633:47;3692:9;3704:5;3708:1;3704;:5;:::i;:::-;3692:17;-1:-1:-1;3737:1:0;3728:5;3732:1;3692:17;3728:5;:::i;:::-;:10;3720:56;;;;;;;19068:2:1;3720:56:0;;;19050:21:1;19107:2;19087:18;;;19080:30;19146:34;19126:18;;;19119:62;19217:3;19197:18;;;19190:31;19238:19;;3720:56:0;18866:397:1;4273:132:0;4331:7;4358:39;4362:1;4365;4358:39;;;;;;;;;;;;;;;;;:3;:39::i;33216:106::-;33274:7;33305:1;33301;:5;:13;;33313:1;33301:13;;;-1:-1:-1;33309:1:0;;33216:106;-1:-1:-1;33216:106:0:o;114858:1542::-;115073:14;115089:4;94667:42;94691:7;94700:8;94667:23;:42::i;:::-;115115:13:::1;::::0;;;::::1;;;115114:14;::::0;:53:::1;;-1:-1:-1::0;115148:10:0::1;115132:27;::::0;;;:15:::1;:27;::::0;;;;;::::1;;:35;;:27:::0;:35:::1;115114:53;115106:96;;;::::0;::::1;::::0;;19470:2:1;115106:96:0::1;::::0;::::1;19452:21:1::0;19509:2;19489:18;;;19482:30;19548:32;19528:18;;;19521:60;19598:18;;115106:96:0::1;19268:354:1::0;115106:96:0::1;115233:1;115221:9;:13;115213:51;;;::::0;::::1;::::0;;19829:2:1;115213:51:0::1;::::0;::::1;19811:21:1::0;19868:2;19848:18;;;19841:30;19907:27;19887:18;;;19880:55;19952:18;;115213:51:0::1;19627:349:1::0;115213:51:0::1;115291:13;;115283:4;:21;;115275:60;;;::::0;::::1;::::0;;16899:2:1;115275:60:0::1;::::0;::::1;16881:21:1::0;16938:2;16918:18;;;16911:30;16977:28;16957:18;;;16950:56;17023:18;;115275:60:0::1;16697:350:1::0;115275:60:0::1;115362:28;;115354:4;:36;;115346:75;;;::::0;::::1;::::0;;17254:2:1;115346:75:0::1;::::0;::::1;17236:21:1::0;17293:2;17273:18;;;17266:30;17332:29;17312:18;;;17305:57;17379:18;;115346:75:0::1;17052:351:1::0;115346:75:0::1;115434:23;115460:20;115475:4;115460:14;:20::i;:::-;115579:33;::::0;::::1;115491:14;115579:33:::0;;;:17:::1;:33;::::0;;;;;;;;115518:95;;20227:66:1;20214:2;20210:15;;;20206:88;115518:95:0;;::::1;20194:101:1::0;;;;20311:12;;;20304:28;;;20348:12;;;20341:28;;;20385:12;;;20378:28;115434:46:0;;-1:-1:-1;115491:14:0;20422:13:1;;115518:95:0::1;::::0;;;;;::::1;::::0;;;;;;115508:106;;115518:95:::1;115508:106:::0;;::::1;::::0;115625:28:::1;::::0;::::1;;::::0;;;:12:::1;:28:::0;;;;;115659:167:::1;::::0;::::1;::::0;;;;;;;::::1;::::0;;;;;;;;;115508:106;;-1:-1:-1;115625:28:0;115659:167;;;115760:25:::1;115706:15:::0;115780:4;115760:19:::1;:25::i;:::-;115659:167:::0;;::::1;::::0;;::::1;::::0;;;115625:202;;::::1;::::0;;::::1;::::0;;-1:-1:-1;115625:202: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;115932:12:::1;::::0;115892:96:::1;::::0;115932:12:::1;;115947:14:::0;115971:4:::1;115978:9:::0;115892:31:::1;:96::i;:::-;116058:23;::::0;:38:::1;::::0;116086:9;116058:27:::1;:38::i;:::-;116032:23;:64:::0;116143:33:::1;::::0;::::1;;::::0;;;:17:::1;:33;::::0;;;;;:48:::1;::::0;116181:9;116143:37:::1;:48::i;:::-;116107:33;::::0;::::1;;::::0;;;:17:::1;:33;::::0;;;;:84;;;;116260:46:::1;::::0;116125:14;;116260:23:::1;:46::i;:::-;116324:68;::::0;;20677:25:1;;;20733:2;20718:18;;20711:34;;;20761:18;;;20754:34;;;116324:68:0::1;20824:55:1::0;;;20819:2;20804:18;;20797:83;116324:68:0;::::1;::::0;::::1;::::0;20664:3:1;20649:19;116324:68:0::1;;;;;;;115095:1305;;114858:1542:::0;;;;;;;:::o;118838:902::-;118962:15;118979;118937:8;118947:4;94667:42;94691:7;94700:8;94667:23;:42::i;:::-;119017:18:::1;::::0;::::1;;::::0;;;:8:::1;:18;::::0;;;;;;;;119056:8:::1;:18:::0;;;;;;;119017;;-1:-1:-1;119056:18:0;-1:-1:-1;119091:11:0;;119087:264:::1;;119119:18;::::0;;::::1;119140:1;119119:18:::0;;;:8:::1;:18;::::0;;;;;:22;;;;119156:13:::1;::::0;;:52;;;;;14097:55:1;;;119156:52:0;;::::1;14079:74:1::0;;;;14169:18;;;14162:34;;;119156:13:0;::::1;::::0;:22:::1;::::0;14052:18:1;;119156:52:0::1;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;119238:7;119223:11;;:22;;;;;;;:::i;:::-;::::0;;;-1:-1:-1;;119303:13:0::1;::::0;119265:74:::1;::::0;;21093:25:1;;;119265:74:0::1;119303:13:::0;;::::1;21210:2:1::0;21195:18;;21188:43;21267:15;;;21247:18;;;21240:43;119265:74:0;;;;::::1;::::0;::::1;::::0;;;;21081:2:1;119265:74:0;;::::1;119087:264;119367:11:::0;;119363:264:::1;;119395:18;::::0;;::::1;119416:1;119395:18:::0;;;:8:::1;:18;::::0;;;;;:22;;;;119432:13:::1;::::0;:52;;;;;14097:55:1;;;119432:52:0::1;::::0;::::1;14079:74:1::0;14169:18;;;14162:34;;;119432:13:0;::::1;::::0;:22:::1;::::0;14052:18:1;;119432:52:0::1;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;119514:7;119499:11;;:22;;;;;;;:::i;:::-;::::0;;;-1:-1:-1;;119579:13:0::1;::::0;119541:74:::1;::::0;;21093:25:1;;;119541:74:0::1;119579:13:::0;;::::1;21210:2:1::0;21195:18;;21188:43;21267:15;;;21247:18;;;21240:43;119541:74:0;;;;::::1;::::0;::::1;::::0;;;;21081:2:1;119541:74:0;;::::1;119363:264;-1:-1:-1::0;;119685:29:0::1;::::0;;::::1;;::::0;;;:19:::1;:29;::::0;;;;119717:15:::1;119685:47:::0;;118838:902;;-1:-1:-1;118838:902:0:o;116962:1378::-;117140:47;117151:14;117167:19;117140:10;:47::i;:::-;;;117201:28;117231:21;117256:33;117266:14;117282:6;117256:9;:33::i;:::-;117308:16;;117200:89;;-1:-1:-1;117200:89:0;-1:-1:-1;117308:26:0;;117300:54;;;;;;;21496:2:1;117300:54:0;;;21478:21:1;21535:2;21515:18;;;21508:30;21574:17;21554:18;;;21547:45;21609:18;;117300:54:0;21294:339:1;117300:54:0;117392:9;:26;;;117373:15;:45;;:71;;;-1:-1:-1;117422:14:0;;;;;;;;:22;;:14;:22;117373:71;:110;;;-1:-1:-1;117464:10:0;117448:27;;;;:15;:27;;;;;;;;:35;;:27;:35;117373:110;117365:145;;;;;;;21840:2:1;117365:145:0;;;21822:21:1;21879:2;21859:18;;;21852:30;21918:24;21898:18;;;21891:52;21960:18;;117365:145:0;21638:346:1;117365:145:0;117543:19;;;;117579:13;;117575:756;;117670:23;;:38;;117698:9;117670:27;:38::i;:::-;117644:23;:64;117759:33;;;;;;;:17;:33;;;;;;:48;;117797:9;117759:37;:48::i;:::-;117723:33;;;;;;;:17;:33;;;;;;;;:84;;;;117879:12;:28;;;:43;;117908:13;;117879:43;;;;;;:::i;:::-;;;;;;;;;;;;;117872:50;;;;;;;;;;;;;;;;;;;;;;;;;;117999:46;;118023:14;;117999:23;:46::i;:::-;118174:12;;:53;;;;;:12;14097:55:1;;;118174:53:0;;;14079:74:1;14169:18;;;14162:34;;;118174:12:0;;;;:21;;14052:18:1;;118174:53:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;118249:70:0;;;22191:25:1;;;22247:2;22232:18;;22225:34;;;118249:70:0;22295:55:1;;;22275:18;;;22268:83;118249:70:0;;;;;;;;;;;22179:2:1;118249:70:0;;;117575:756;117066:1274;;;116962:1378;;;:::o;109240:1543::-;109430:8;109426:46;;;109454:6;:4;:6::i;:::-;109496:21;;;;109492:1284;;109710:27;109756:28;109803:27;109848:30;109870:7;109848:21;:30::i;:::-;109688:190;;;;;;109940:20;109952:7;109940:11;:20::i;:::-;110036:31;;;;;;;:22;:31;;;;;:54;;;110177:42;;;110173:590;;110240:19;110262:44;:19;110286;110262:23;:44::i;:::-;110350:22;;110240:66;;-1:-1:-1;110350:39:0;;110240:66;110350:26;:39::i;:::-;110325:22;:64;110437:36;:19;110461:11;110437:23;:36::i;:::-;110408:26;;;;;;;:17;:26;;;;;:65;-1:-1:-1;110173:590:0;;;110514:19;110536:44;:19;110560;110536:23;:44::i;:::-;110624:22;;110514:66;;-1:-1:-1;110624:39:0;;110514:66;110624:26;:39::i;:::-;110599:22;:64;110711:36;:19;110735:11;110711:23;:36::i;:::-;110682:26;;;;;;;:17;:26;;;;;:65;-1:-1:-1;110173:590:0;109519:1257;;;109240:1543;;:::o;108724:508::-;108806:31;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;108806:31:0;108839:15;;108867:280;108891:28;;;;;;;:12;:28;;;;;:35;108887:39;;108867:280;;;108962:28;;;;;;;:12;:28;;;;;:31;;108991:1;;108962:31;;;;;;:::i;:::-;;;;;;;;;;;:38;;;108952:6;:48;108948:188;;109035:28;;;;;;;:12;:28;;;;;:31;;109064:1;;109035:31;;;;;;:::i;:::-;;;;;;;;;;;109020:46;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;109095:1;109085:11;;109115:5;;108948:188;108928:3;;;;:::i;:::-;;;;108867:280;;;-1:-1:-1;109165:19:0;;:29;;109157:57;;;;;;;21496:2:1;109157:57:0;;;21478:21:1;21535:2;21515:18;;;21508:30;21574:17;21554:18;;;21547:45;21609:18;;109157:57:0;21294:339:1;109157:57:0;108724:508;;;;;:::o;36033:402::-;36258:51;;;36247:10;22643:15:1;;;36258:51:0;;;22625:34:1;22695:15;;;22675:18;;;22668:43;22727:18;;;;22720:34;;;36258:51:0;;;;;;;;;;22537:18:1;;;;36258:51:0;;;;;;;;;;;;;36247:63;;-1:-1:-1;;;;36247:10:0;;;;:63;;36258:51;36247:63;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;36211:99;;;;36329:7;:57;;;;-1:-1:-1;36341:11:0;;:16;;:44;;;36372:4;36361:24;;;;;;;;;;;;:::i;:::-;36321:106;;;;;;;23514:2:1;36321:106:0;;;23496:21:1;23553:2;23533:18;;;23526:30;23592:34;23572:18;;;23565:62;23663:6;23643:18;;;23636:34;23687:19;;36321:106:0;23312:400:1;97731:133:0;97790:7;97817:39;97826:15;97843:12;;97817:8;:39::i;:::-;97810:46;;97731:133;:::o;119789:2039::-;119889:8;;119881:31;119889:8;119881:31;;;;119880:95;;-1:-1:-1;119959:15:0;;119940:14;;119918:37;;119919:15;;119918:21;:37::i;:::-;:56;;119880:95;119876:201;;;119991:8;;;;;;;;;;;:25;;;:27;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;120050:15:0;120033:14;:32;119876:201;120160:13;;;:38;;;;;120192:4;120160:38;;;805:74:1;;;;120139:18:0;;120160:13;;;;;:23;;778:18:1;;120160:38:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;120230:13;;:38;;;;;120262:4;120230:38;;;805:74:1;120139:59:0;;-1:-1:-1;120209:18:0;;120230:13;;;;;:23;;778:18:1;;120230:38:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;120209:59;;120406:29;120438:64;120447:37;120469:14;;120448:15;120447:21;;:37;;;;:::i;:::-;120486:15;;120438:8;:64::i;:::-;120532:11;;120406:96;;-1:-1:-1;120532:38:0;;120406:96;120532:15;:38::i;:::-;120517:11;;:53;;;;;;;:::i;:::-;;;;-1:-1:-1;;120600:11:0;;:38;;120616:21;120600:15;:38::i;:::-;120585:11;;:53;;;;;;;:::i;:::-;;;;;;;;120391:259;120720:15;120737;120756:16;:14;:16::i;:::-;120787:21;:31;;;;120833:21;:31;-1:-1:-1;;121056:11:0;;121040;;-1:-1:-1;;121040:28:0;;:11;:15;:28::i;:::-;121022:46;;121083:15;121101:28;121117:11;;121101;;:15;;:28;;;;:::i;:::-;121083:46;;121201:7;121187:10;:21;121183:287;;121299:1;121285:11;:15;121183:287;;;121354:13;121370:23;:10;121385:7;121370:14;:23::i;:::-;121354:39;;121426:28;121438:15;;121427:5;121426:11;;:28;;;;:::i;:::-;121412:11;:42;-1:-1:-1;121183:287:0;121541:7;121527:10;:21;121523:287;;121639:1;121625:11;:15;121523:287;;;121694:13;121710:23;:10;121725:7;121710:14;:23::i;:::-;121694:39;;121766:28;121778:15;;121767:5;121766:11;;:28;;;;:::i;:::-;121752:11;:42;-1:-1:-1;120956:865:0;;119821:2007;;119789:2039::o;2891:192::-;2977:7;3013:12;3005:6;;;;2997:29;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;3037:9:0;3049:5;3053:1;3049;:5;:::i;:::-;3037:17;2891:192;-1:-1:-1;;;;;2891:192:0:o;4935:345::-;5021:7;5123:12;5116:5;5108:28;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;5147:9:0;5159:5;5163:1;5159;:5;:::i;113408:436::-;113470:21;;;;113466:371;;113548:15;113565;113584;113591:7;113584:6;:15::i;:::-;113614:17;;;;;;;:8;:17;;;;;;;;:27;;;;113656:8;:17;;;;;:27;;;;113733:21;;113698:23;:32;;;;;:56;113804:21;;113769:23;:32;;;;;;;:56;-1:-1:-1;;113466:371:0;113408:436;:::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;890:180::-;949:6;1002:2;990:9;981:7;977:23;973:32;970:52;;;1018:1;1015;1008:12;970:52;-1:-1:-1;1041:23:1;;890:180;-1:-1:-1;890:180:1:o;1257:248::-;1325:6;1333;1386:2;1374:9;1365:7;1361:23;1357:32;1354:52;;;1402:1;1399;1392:12;1354:52;-1:-1:-1;;1425:23:1;;;1495:2;1480:18;;;1467:32;;-1:-1:-1;1257:248:1:o;1756:1011::-;1985:2;2037:21;;;2107:13;;2010:18;;;2129:22;;;1956:4;;1985:2;2170;;2188:18;;;;2229:15;;;1956:4;2272:469;2286:6;2283:1;2280:13;2272:469;;;2345:13;;2383:9;;2371:22;;2433:11;;;2427:18;2413:12;;;2406:40;2486:11;;;2480:18;2466:12;;;2459:40;2522:4;2566:11;;;2560:18;2546:12;;;2539:40;2602:4;2646:11;;;2640:18;2626:12;;;2619:40;2688:4;2679:14;;;;2716:15;;;;2308:1;2301:9;2272:469;;;-1:-1:-1;2758:3:1;;1756:1011;-1:-1:-1;;;;;;;1756:1011:1:o;2772:391::-;2858:6;2866;2874;2882;2935:3;2923:9;2914:7;2910:23;2906:33;2903:53;;;2952:1;2949;2942:12;2903:53;2975:29;2994:9;2975:29;:::i;:::-;2965:39;3051:2;3036:18;;3023:32;;-1:-1:-1;3102:2:1;3087:18;;3074:32;;3153:2;3138:18;3125:32;;-1:-1:-1;2772:391:1;-1:-1:-1;;;2772:391:1:o;3545:316::-;3622:6;3630;3638;3691:2;3679:9;3670:7;3666:23;3662:32;3659:52;;;3707:1;3704;3697:12;3659:52;-1:-1:-1;;3730:23:1;;;3800:2;3785:18;;3772:32;;-1:-1:-1;3851:2:1;3836:18;;;3823:32;;3545:316;-1:-1:-1;3545:316:1:o;4120:254::-;4188:6;4196;4249:2;4237:9;4228:7;4224:23;4220:32;4217:52;;;4265:1;4262;4255:12;4217:52;4288:29;4307:9;4288:29;:::i;:::-;4278:39;4364:2;4349:18;;;;4336:32;;-1:-1:-1;;;4120:254:1:o;5416:260::-;5484:6;5492;5545:2;5533:9;5524:7;5520:23;5516:32;5513:52;;;5561:1;5558;5551:12;5513:52;5584:29;5603:9;5584:29;:::i;:::-;5574:39;;5632:38;5666:2;5655:9;5651:18;5632:38;:::i;:::-;5622:48;;5416:260;;;;;:::o;7067:184::-;7119:77;7116:1;7109:88;7216:4;7213:1;7206:15;7240:4;7237:1;7230:15;7256:168;7329:9;;;7360;;7377:15;;;7371:22;;7357:37;7347:71;;7398:18;;:::i;7429:274::-;7469:1;7495;7485:189;;7530:77;7527:1;7520:88;7631:4;7628:1;7621:15;7659:4;7656:1;7649:15;7485:189;-1:-1:-1;7688:9:1;;7429:274::o;8823:184::-;8893:6;8946:2;8934:9;8925:7;8921:23;8917:32;8914:52;;;8962:1;8959;8952:12;8914:52;-1:-1:-1;8985:16:1;;8823:184;-1:-1:-1;8823:184:1:o;11121:273::-;11189:6;11242:2;11230:9;11221:7;11217:23;11213:32;11210:52;;;11258:1;11255;11248:12;11210:52;11290:9;11284:16;11340:4;11333:5;11329:16;11322:5;11319:27;11309:55;;11360:1;11357;11350:12;12699:184;12751:77;12748:1;12741:88;12848:4;12845:1;12838:15;12872:4;12869:1;12862:15;12888:128;12955:9;;;12976:11;;;12973:37;;;12990:18;;:::i;13021:125::-;13086:9;;;13107:10;;;13104:36;;;13120:18;;:::i;14207:277::-;14274:6;14327:2;14315:9;14306:7;14302:23;14298:32;14295:52;;;14343:1;14340;14333:12;14295:52;14375:9;14369:16;14428:5;14421:13;14414:21;14407:5;14404:32;14394:60;;14450:1;14447;14440:12;14489:195;14528:3;14559:66;14552:5;14549:77;14546:103;;14629:18;;:::i;:::-;-1:-1:-1;14676:1:1;14665:13;;14489:195::o;22765:250::-;22850:1;22860:113;22874:6;22871:1;22868:13;22860:113;;;22950:11;;;22944:18;22931:11;;;22924:39;22896:2;22889:10;22860:113;;;-1:-1:-1;;23007:1:1;22989:16;;22982:27;22765:250::o;23020:287::-;23149:3;23187:6;23181:13;23203:66;23262:6;23257:3;23250:4;23242:6;23238:17;23203:66;:::i;:::-;23285:16;;;;;23020:287;-1:-1:-1;;23020:287:1:o;23717:455::-;23866:2;23855:9;23848:21;23829:4;23898:6;23892:13;23941:6;23936:2;23925:9;23921:18;23914:34;23957:79;24029:6;24024:2;24013:9;24009:18;24004:2;23996:6;23992:15;23957:79;:::i;:::-;24088:2;24076:15;24093:66;24072:88;24057:104;;;;24163:2;24053:113;;23717:455;-1:-1:-1;;23717:455:1:o
Metadata Hash
8e51b29d8d870a62977c02553a5484997e40b9298e16fde38690de78adbaffc6
Age | Block | Fee Address | BC Fee Address | Voting Power | Jailed | Incoming |
---|
Make sure to use the "Vote Down" button for any spammy posts, and the "Vote Up" for interesting conversations.