Source Code
Latest 25 from a total of 3,391 transactions
| Transaction Hash |
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
| Get Reward | 31230684 | 6 hrs ago | IN | 0 FRAX | 0.00001617 | ||||
| Get Reward | 31185680 | 31 hrs ago | IN | 0 FRAX | 0.00002644 | ||||
| Get Reward | 31180086 | 34 hrs ago | IN | 0 FRAX | 0.00000687 | ||||
| Get Reward | 31179953 | 35 hrs ago | IN | 0 FRAX | 0.00000714 | ||||
| Get Reward | 31145702 | 2 days ago | IN | 0 FRAX | 0.00001201 | ||||
| Get Reward | 31135325 | 2 days ago | IN | 0 FRAX | 0.00000633 | ||||
| Get Reward | 31124801 | 2 days ago | IN | 0 FRAX | 0.00000455 | ||||
| Get Reward | 31106404 | 3 days ago | IN | 0 FRAX | 0.00001109 | ||||
| Get Reward | 31099928 | 3 days ago | IN | 0 FRAX | 0.00003009 | ||||
| Get Reward | 31092928 | 3 days ago | IN | 0 FRAX | 0.00000807 | ||||
| Get Reward | 31079341 | 3 days ago | IN | 0 FRAX | 0.00000439 | ||||
| Lock Longer | 31079330 | 3 days ago | IN | 0 FRAX | 0.00000439 | ||||
| Get Reward | 31079322 | 3 days ago | IN | 0 FRAX | 0.00000409 | ||||
| Get Reward | 31079304 | 3 days ago | IN | 0 FRAX | 0.00000431 | ||||
| Get Reward | 31079290 | 3 days ago | IN | 0 FRAX | 0.00000408 | ||||
| Get Reward | 31079254 | 3 days ago | IN | 0 FRAX | 0.00000441 | ||||
| Get Reward | 31070437 | 3 days ago | IN | 0 FRAX | 0.00000488 | ||||
| Lock Longer | 31048746 | 4 days ago | IN | 0 FRAX | 0.0000049 | ||||
| Get Reward | 31044443 | 4 days ago | IN | 0 FRAX | 0.00000703 | ||||
| Get Reward | 31037450 | 4 days ago | IN | 0 FRAX | 0.00000434 | ||||
| Get Reward | 31004720 | 5 days ago | IN | 0 FRAX | 0.00000433 | ||||
| Get Reward | 30983680 | 6 days ago | IN | 0 FRAX | 0.00000363 | ||||
| Lock Additional | 30971918 | 6 days ago | IN | 0 FRAX | 0.00000203 | ||||
| Get Reward | 30970888 | 6 days ago | IN | 0 FRAX | 0.0000027 | ||||
| Get Reward | 30969816 | 6 days ago | IN | 0 FRAX | 0.00000297 |
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Latest 25 Deposits
Cross-Chain Transactions
Loading...
Loading
Contract Name:
FraxCCFarmV4_cvxLP
Compiler Version
v0.8.23+commit.f704f362
Contract Source Code (Solidity)
/**
*Submitted for verification at fraxscan.com on 2024-02-27
*/
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.8.0;
// Sources flattened with hardhat v2.19.4 https://hardhat.org
// File contracts/Common/Context.sol
// Original license: SPDX_License_Identifier: MIT
/*
* @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
// Original license: SPDX_License_Identifier: MIT
/**
* @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
// Original license: SPDX_License_Identifier: MIT
/**
* @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
// Original license: SPDX_License_Identifier: MIT
/**
* @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
// Original license: SPDX_License_Identifier: MIT
/**
* @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
// Original license: SPDX_License_Identifier: MIT
/**
* @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
// Original license: SPDX_License_Identifier: MIT
/**
* @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
// Original license: SPDX_License_Identifier: GPL-2.0-or-later
// 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
// Original license: SPDX_License_Identifier: MIT
// 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
// Original license: SPDX_License_Identifier: MIT
/**
* @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
// Original license: SPDX_License_Identifier: GPL-2.0-or-later
// ====================================================================
// | ______ _______ |
// | / _____________ __ __ / ____(_____ ____ _____ ________ |
// | / /_ / ___/ __ `| |/_/ / /_ / / __ \/ __ `/ __ \/ ___/ _ \ |
// | / __/ / / / /_/ _> < / __/ / / / / / /_/ / / / / /__/ __/ |
// | /_/ /_/ \__,_/_/|_| /_/ /_/_/ /_/\__,_/_/ /_/\___/\___/ |
// | |
// ====================================================================
// ====================== 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
// Original license: SPDX_License_Identifier: MIT
/**
* @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
// Original license: SPDX_License_Identifier: MIT
/**
* @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
// Original license: SPDX_License_Identifier: MIT
/**
* @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
// Original license: SPDX_License_Identifier: MIT
/**
* @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
// Original license: SPDX_License_Identifier: MIT
/**
* @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
// Original license: SPDX_License_Identifier: GPL-2.0-or-later
// ====================================================================
// | ______ _______ |
// | / _____________ __ __ / ____(_____ ____ _____ ________ |
// | / /_ / ___/ __ `| |/_/ / /_ / / __ \/ __ `/ __ \/ ___/ _ \ |
// | / __/ / / / /_/ _> < / __/ / / / / / /_/ / / / / /__/ __/ |
// | /_/ /_/ \__,_/_/|_| /_/ /_/_/ /_/\__,_/_/ /_/\___/\___/ |
// | |
// ====================================================================
// ======================== 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
// Original license: SPDX_License_Identifier: MIT
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/Fraxswap/core/interfaces/IUniswapV2PairV5.sol
interface IUniswapV2PairV5 {
event Approval(address indexed owner, address indexed spender, uint value);
event Transfer(address indexed from, address indexed to, uint value);
function name() external pure returns (string memory);
function symbol() external pure returns (string memory);
function decimals() external pure returns (uint8);
function totalSupply() external view returns (uint);
function balanceOf(address owner) external view returns (uint);
function allowance(address owner, address spender) external view returns (uint);
function approve(address spender, uint value) external returns (bool);
function transfer(address to, uint value) external returns (bool);
function transferFrom(address from, address to, uint value) external returns (bool);
function DOMAIN_SEPARATOR() external view returns (bytes32);
function PERMIT_TYPEHASH() external pure returns (bytes32);
function nonces(address owner) external view returns (uint);
function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external;
event Mint(address indexed sender, uint amount0, uint amount1);
event Burn(address indexed sender, uint amount0, uint amount1, address indexed to);
event Swap(
address indexed sender,
uint amount0In,
uint amount1In,
uint amount0Out,
uint amount1Out,
address indexed to
);
event Sync(uint112 reserve0, uint112 reserve1);
function MINIMUM_LIQUIDITY() external pure returns (uint);
function factory() external view returns (address);
function token0() external view returns (address);
function token1() external view returns (address);
function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast);
function price0CumulativeLast() external view returns (uint);
function price1CumulativeLast() external view returns (uint);
function kLast() external view returns (uint);
function mint(address to) external returns (uint liquidity);
function burn(address to) external returns (uint amount0, uint amount1);
function swap(uint amount0Out, uint amount1Out, address to, bytes calldata data) external;
function skim(address to) external;
function sync() external;
function initialize(address, address) external;
}
// File contracts/Fraxswap/core/interfaces/IFraxswapPair.sol
// Original license: SPDX_License_Identifier: GPL-2.0-or-later
// ====================================================================
// | ______ _______ |
// | / _____________ __ __ / ____(_____ ____ _____ ________ |
// | / /_ / ___/ __ `| |/_/ / /_ / / __ \/ __ `/ __ \/ ___/ _ \ |
// | / __/ / / / /_/ _> < / __/ / / / / / /_/ / / / / /__/ __/ |
// | /_/ /_/ \__,_/_/|_| /_/ /_/_/ /_/\__,_/_/ /_/\___/\___/ |
// | |
// ====================================================================
// ========================= IFraxswapPair ==========================
// ====================================================================
// Fraxswap LP Pair Interface
// Inspired by https://www.paradigm.xyz/2021/07/twamm
// https://github.com/para-dave/twamm
// Frax Finance: https://github.com/FraxFinance
// Primary Author(s)
// Rich Gee: https://github.com/zer0blockchain
// Dennis: https://github.com/denett
// Reviewer(s) / Contributor(s)
// Travis Moore: https://github.com/FortisFortuna
// Sam Kazemian: https://github.com/samkazemian
interface IFraxswapPair is IUniswapV2PairV5 {
// TWAMM
event LongTermSwap0To1(address indexed addr, uint256 orderId, uint256 amount0In, uint256 numberOfTimeIntervals);
event LongTermSwap1To0(address indexed addr, uint256 orderId, uint256 amount1In, uint256 numberOfTimeIntervals);
event CancelLongTermOrder(address indexed addr, uint256 orderId, address sellToken, uint256 unsoldAmount, address buyToken, uint256 purchasedAmount);
event WithdrawProceedsFromLongTermOrder(address indexed addr, uint256 orderId, address indexed proceedToken, uint256 proceeds, bool orderExpired);
function fee() external view returns (uint);
function longTermSwapFrom0To1(uint256 amount0In, uint256 numberOfTimeIntervals) external returns (uint256 orderId);
function longTermSwapFrom1To0(uint256 amount1In, uint256 numberOfTimeIntervals) external returns (uint256 orderId);
function cancelLongTermSwap(uint256 orderId) external;
function withdrawProceedsFromLongTermSwap(uint256 orderId) external returns (bool is_expired, address rewardTkn, uint256 totalReward);
function executeVirtualOrders(uint256 blockTimestamp) external;
function getAmountOut(uint amountIn, address tokenIn) external view returns (uint);
function getAmountIn(uint amountOut, address tokenOut) external view returns (uint);
function orderTimeInterval() external returns (uint256);
function getTWAPHistoryLength() external view returns (uint);
function getTwammReserves() external view returns (uint112 _reserve0, uint112 _reserve1, uint32 _blockTimestampLast, uint112 _twammReserve0, uint112 _twammReserve1, uint256 _fee);
function getReserveAfterTwamm(uint256 blockTimestamp) external view returns (uint112 _reserve0, uint112 _reserve1, uint256 lastVirtualOrderTimestamp, uint112 _twammReserve0, uint112 _twammReserve1);
function getNextOrderID() external view returns (uint256);
function getOrderIDsForUser(address user) external view returns (uint256[] memory);
function getOrderIDsForUserLength(address user) external view returns (uint256);
// function getDetailedOrdersForUser(address user, uint256 offset, uint256 limit) external view returns (LongTermOrdersLib.Order[] memory detailed_orders);
function twammUpToDate() external view returns (bool);
function getTwammState() external view returns (uint256 token0Rate, uint256 token1Rate, uint256 lastVirtualOrderTimestamp, uint256 orderTimeInterval_rtn, uint256 rewardFactorPool0, uint256 rewardFactorPool1);
function getTwammSalesRateEnding(uint256 _blockTimestamp) external view returns (uint256 orderPool0SalesRateEnding, uint256 orderPool1SalesRateEnding);
function getTwammRewardFactor(uint256 _blockTimestamp) external view returns (uint256 rewardFactorPool0AtTimestamp, uint256 rewardFactorPool1AtTimestamp);
function getTwammOrder(uint256 orderId) external view returns (uint256 id, uint256 creationTimestamp, uint256 expirationTimestamp, uint256 saleRate, address owner, address sellTokenAddr, address buyTokenAddr);
function getTwammOrderProceedsView(uint256 orderId, uint256 blockTimestamp) external view returns (bool orderExpired, uint256 totalReward);
function getTwammOrderProceeds(uint256 orderId) external returns (bool orderExpired, uint256 totalReward);
function togglePauseNewSwaps() external;
}
// File contracts/Curve/IveFXS.sol
// Original license: SPDX_License_Identifier: GPL-2.0-or-later
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
// Original license: SPDX_License_Identifier: GPL-2.0-or-later
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/Staking/FraxCrossChainFarmV4_ERC20.sol
// Original license: SPDX_License_Identifier: GPL-2.0-or-later
// ====================================================================
// | ______ _______ |
// | / _____________ __ __ / ____(_____ ____ _____ ________ |
// | / /_ / ___/ __ `| |/_/ / /_ / / __ \/ __ `/ __ \/ ___/ _ \ |
// | / __/ / / / /_/ _> < / __/ / / / / / /_/ / / / / /__/ __/ |
// | /_/ /_/ \__,_/_/|_| /_/ /_/_/ /_/\__,_/_/ /_/\___/\___/ |
// | |
// ====================================================================
// ==================== FraxCrossChainFarmV4_ERC20 ====================
// ====================================================================
// 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
// V4: Adds variable number of rewards by using arrays instead of fixed names
// 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/balancer/IBalancerVault.sol'; // Balancer frxETH-bb-a-WETH Gauge
// import '../Misc_AMOs/balancer/IBalancerChildLiquidityGauge.sol'; // Balancer frxETH-bb-a-WETH Gauge
// import '../Misc_AMOs/balancer/IL2BalancerPseudoMinter.sol'; // Balancer frxETH-bb-a-WETH Gauge
// import '../Misc_AMOs/balancer/IStablePool.sol'; // Balancer frxETH-bb-a-WETH Gauge
// import "../Oracle/AggregatorV3Interface.sol"; // Balancer frxETH-bb-a-WETH Gauge and Convex frxETH/XXXETH
// import '../Misc_AMOs/convex/IConvexCvxLPRewardPoolCombo.sol'; // Convex cvxLP/RewardPool Combo
// import '../Misc_AMOs/curve/ICurveChildLiquidityGauge.sol'; // Convex cvxLP/RewardPool Combo
// import '../Misc_AMOs/curve/I2pool.sol'; // Curve 2-token
// import '../Misc_AMOs/curve/I2poolTokenNoLending.sol'; // Curve 2-token (No Lending)
// import '../Misc_AMOs/curve/I3pool.sol'; // Curve 3-token
// import '../Misc_AMOs/curve/I3poolAndToken.sol'; // Curve 3-token with pool
// import '../Misc_AMOs/curve/ICurveStableSwapNG.sol'; // Curve 2-token Stable NG
// Inheritance
/// @title FraxCrossChainFarmV4_ERC20
/// @notice Used as a farm, usually fed by rewards dropped in from various sources
contract FraxCrossChainFarmV4_ERC20 is Owned, ReentrancyGuard {
using SafeMath for uint256;
using SafeERC20 for ERC20;
/* ========== STATE VARIABLES ========== */
/// @notice Future address of veFXS, if applicable
IveFXS public veFXS;
/// @notice Array of all the reward tokens
address[] public rewardTokens;
// // KyberSwap Elastic
// // Manually set during deploy
// // ===================================================================
// // <>KYBERSWAP<>KYBERSWAP<>KYBERSWAP<>KYBERSWAP<>KYBERSWAP<>KYBERSWAP<>KYBERSWAP<>
// IKyberSwapFarmingToken public stakingToken; // KyberSwap Elastic
// ComboOracle_KyberSwapElasticV2 public KSE_ComboOracleV2 = ComboOracle_KyberSwapElasticV2(0xfBCB0F967817c924f83e26e04F0FB28ED4d6276F); // KyberSwap Elastic
// IKyberFactory public immutable kyber_factory = IKyberFactory(0xC7a590291e07B9fe9E64b86c58fD8fC764308C4A); // KyberSwap Elastic
// // Need to seed a starting token to use both as a basis for fraxPerLPToken
// // as well as getting ticks, etc
// uint256 public seed_token_id = 7366;
// function setSeedTokenID(uint256 _seed_token_id) public onlyByOwnGov {
// seed_token_id = _seed_token_id;
// }
// function setKyberSwapElasticComboOracle(address _kse_combo_oracle_address) public onlyByOwnGov {
// KSE_ComboOracleV2 = ComboOracle_KyberSwapElasticV2(_kse_combo_oracle_address);
// }
// // <>KYBERSWAP<>KYBERSWAP<>KYBERSWAP<>KYBERSWAP<>KYBERSWAP<>KYBERSWAP<>KYBERSWAP<>
// Balancer frxETH-bb-a-WETH Gauge or Convex frxETH/XXXETH
// IBalancerChildLiquidityGauge public stakingToken; // Balancer frxETH-bb-a-WETH Gauge
// AggregatorV3Interface internal priceFeedETHUSD = AggregatorV3Interface(0x639Fe6ab55C921f74e7fac1ee960C0B6293ba612); // For Balancer frxETH-bb-a-WETH Gauge
// function setETHUSDOracle(address _eth_usd_oracle_address) public onlyByOwnGov {
// require(_eth_usd_oracle_address != address(0), "Zero address detected");
// priceFeedETHUSD = AggregatorV3Interface(_eth_usd_oracle_address);
// }
// function getLatestETHPriceE8() public view returns (int) {
// // Returns in E8
// (uint80 roundID, int price, , uint256 updatedAt, uint80 answeredInRound) = priceFeedETHUSD.latestRoundData();
// require(price >= 0 && updatedAt!= 0 && answeredInRound >= roundID, "Invalid chainlink price");
// return price;
// }
/// @notice The token being staked
// I2pool public stakingToken; // Curve 2-token
// I3pool public stakingToken; // Curve 3-token
// I3poolAndToken public stakingToken; // Curve 3-token with pool
// IConvexCvxLPRewardPoolCombo public stakingToken; // Convex cvxLP/RewardPool combo
IFraxswapPair public stakingToken; // Fraxswap V2
// IStableXPair public stakingToken; // Impossible
// IFeederPool public stakingToken; // mStable
// ISaddleLPToken public stakingToken; // Saddle L2D4
// ILToken public stakingToken; // Sentiment LFrax
// ILPToken public stakingToken; // Snowball S4D
// IUniswapV2Pair public stakingToken; // Uniswap V2
/// @notice An address where rewards are pulled from, if applicable
FraxCrossChainRewarder public rewarder;
/// @notice The address of FRAX
address public fraxAddress;
/// @notice Constant for various precisions
uint256 private constant MULTIPLIER_PRECISION = 1e18;
/// @notice Governance timelock address
address public timelockAddress;
/// @notice Gauge controller, if present
address public controllerAddress;
/// @notice The time the rewards period should finish
uint256 public periodFinish;
/// @notice The last time this contract was updated
uint256 public lastUpdateTime;
/// @notice The max weight multiplier you can get for locking your position
uint256 public lock_max_multiplier = uint256(3e18); // E18. 1x = e18
/// @notice The lock time needed to get the max weight multiplier
uint256 public lock_time_for_max_multiplier = 3 * 365 * 86400; // 3 years
/// @notice The minimum lock time required
uint256 public lock_time_min = 1; // 1 second
/// @notice How much veFXS you must have, per Frax in the LP, in order to get the veFXS boost, if applicable
uint256 public vefxs_per_frax_for_max_boost = uint256(4e18); // E18. 4e18 means 4 veFXS must be held by the staker per 1 FRAX
/// @notice The max weight multiplier you can get for having veFXS
uint256 public vefxs_max_multiplier = uint256(2e18); // E18. 1x = 1e18
/// @notice Tracks the veFXS multiplier of a user
mapping(address => uint256) private _vefxsMultiplierStored;
/// @notice The reward tokens per second
uint256[] public rewardRates;
/// @notice Helper to see if a token is a reward token on this farm
mapping(address => bool) internal isRewardToken;
/// @notice Helper to get the reward token index, given the address of the token
mapping(address => uint256) public rewardTokenAddrToIdx;
/// @notice The duration of each rewards period
uint256 public rewardsDuration = 604800; // 7 * 86400 (7 days).
/// @notice The total amount of reward tokens owed to all farmers. Always increments
/// @dev Technically ttlRewsOwed - ttlRewsPaid is what is actually uncollected, but both have to always be increasing
/// for the tracking to work
uint256[] public ttlRewsOwed;
/// @notice The total amount of reward tokens paid out to all farmers
uint256[] public ttlRewsPaid;
/// @notice Accumulator for rewardsPerToken
// https://www.paradigm.xyz/2021/05/liquidity-mining-on-uniswap-v3
uint256[] private rewardsPerTokenStored;
/// @notice Accumulator for userRewardsPerTokenPaid
mapping(address => mapping(uint256 => uint256)) private userRewardsPerTokenPaid; // staker addr -> token id -> paid amount
/// @notice Used for tracking current rewards
mapping(address => mapping(uint256 => uint256)) private rewards; // staker addr -> token id -> reward amount
/// @notice The last time rewards were pulled in
uint256 public lastRewardPull;
/// @notice The last time a farmer claimed their rewards
mapping(address => uint256) internal lastRewardClaimTime; // staker addr -> timestamp
/// @notice Total amount of LP in the farm
uint256 private _total_liquidity_locked;
/// @notice Total weight of farmers, which takes LP amount, veFXS balances, and time locked
uint256 private _total_combined_weight;
/// @notice A particular farmer's locked LP balance
mapping(address => uint256) private _locked_liquidity;
/// @notice A particular farmer's weight
mapping(address => uint256) private _combined_weights;
// Uniswap V2 / Impossible ONLY
/// @notice If FRAX is token0
bool frax_is_token0;
/// @notice Locked stake positions for a farmer
mapping(address => LockedStake[]) public lockedStakes;
/// @notice List of valid migrators (set by governance)
mapping(address => bool) public valid_migrators;
/// @notice Stakers set which migrator(s) they want to use
mapping(address => mapping(address => bool)) public staker_allowed_migrators;
/// @notice Used for migrations. Prevents new stakes, but allows LP and reward withdrawals
bool public migrationsOn;
/// @notice Release locked stakes in case of system migration or emergency
bool public stakesUnlocked;
/// @notice If withdrawals are paused
bool public withdrawalsPaused;
/// @notice If reward collections are paused
bool public rewardsCollectionPaused; // For emergencies
/// @notice If staking is paused
bool public stakingPaused; // For emergencies
// For emergencies if a token is overemitted or something else. Only callable once.
// Bypasses certain logic, which will cause reward calculations to be off
// But the goal is for the users to recover LP, and they couldn't claim the erroneous rewards anyways.
// Reward reimbursement claims would be handled with pre-issue earned() snapshots and a claim contract, or similar.
bool public withdrawalOnlyShutdown;
/// @notice If this contract has been initialized
bool public isInitialized;
/// @notice Version
string public version = "0.0.9";
/* ========== STRUCTS ========== */
/// @notice Information about a particular locked stake
/// @param kek_id A unique ID for the stake
/// @param start_timestamp When the stake was locked
/// @param liquidity How much LP the stake has
/// @param ending_timestamp When the stake should be unlocked
/// @param lock_multiplier Initial weight multiplier from the lock time component.
struct LockedStake {
bytes32 kek_id;
uint256 start_timestamp;
uint256 liquidity;
uint256 ending_timestamp;
uint256 lock_multiplier; // 6 decimals of precision. 1x = 1000000
}
/* ========== MODIFIERS ========== */
/// @notice Only governance should be able to call
modifier onlyByOwnGov() {
require(msg.sender == owner || msg.sender == timelockAddress, "Not owner or timelock");
_;
}
/// @notice Only governance or the controller should be able to call
modifier onlyByOwnGovCtrlr() {
require(msg.sender == owner || msg.sender == timelockAddress || msg.sender == controllerAddress, "Not own, tlk, or ctrlr");
_;
}
/// @notice Should be in migration
modifier isMigrating() {
require(migrationsOn == true, "Not in migration");
_;
}
/// @notice Staking should not be paused
modifier notStakingPaused() {
require(!stakingPaused, "Staking paused");
_;
}
/// @notice Update rewards and balances
modifier updateRewardAndBalance(address account, bool sync_too) {
_updateRewardAndBalance(account, sync_too, false);
_;
}
/* ========== CONSTRUCTOR ========== */
/// @notice Constructor
/// @param _owner The owner of the farm
/// @param _rewardTokens Array of reward tokens
/// @param _stakingToken The LP token being staked
/// @param _fraxAddress Address of FRAX
/// @param _timelockAddress Address of the timelock
/// @param _rewarder_address Address of the rewarder contract, if applicable
constructor (
address _owner,
address[] memory _rewardTokens,
address _stakingToken,
address _fraxAddress,
address _timelockAddress,
address _rewarder_address
) Owned(_owner){
// Set state variables
fraxAddress = _fraxAddress;
rewardTokens = _rewardTokens;
// Loop thought the reward tokens
for (uint256 i = 0; i < _rewardTokens.length; i++) {
// For fast token address -> token ID lookups later
rewardTokenAddrToIdx[_rewardTokens[i]] = i;
// Add to the mapping
isRewardToken[_rewardTokens[i]] = true;
// Initialize the stored rewards
rewardsPerTokenStored.push(0);
// Initialize the rewards owed and paid
ttlRewsOwed.push(0);
ttlRewsPaid.push(0);
// Initialize the reward rates
rewardRates.push(0);
}
// stakingToken = IBalancerChildLiquidityGauge(_stakingToken); // Balancer frxETH-bb-a-WETH Gauge
// stakingToken = IConvexCvxLPRewardPoolCombo(_stakingToken);
// stakingToken = I2pool(_stakingToken);
// stakingToken = I3pool(_stakingToken);
// stakingToken = I3poolAndToken(_stakingToken);
// stakingToken = IStableXPair(_stakingToken);
// stakingToken = IFeederPool(_stakingToken);
stakingToken = IFraxswapPair(_stakingToken);
// stakingToken = ISaddleLPToken(_stakingToken);
// stakingToken = ILToken(_stakingToken);
// stakingToken = ILPToken(_stakingToken);
// stakingToken = IUniswapV2Pair(_stakingToken);
// stakingToken = IKyberSwapFarmingToken(_stakingToken); // KyberSwap Elastic
timelockAddress = _timelockAddress;
rewarder = FraxCrossChainRewarder(_rewarder_address);
// Uniswap V2 / Impossible ONLY
// Need to know which token FRAX is (0 or 1)
address token0 = stakingToken.token0();
if (token0 == fraxAddress) 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 ========== */
/// @notice Total locked liquidity tokens
/// @return uint256 Total amount of LP tokens in the farm
function totalLiquidityLocked() external view returns (uint256) {
return _total_liquidity_locked;
}
/// @notice Locked liquidity for a given account
/// @return uint256 Total amount of LP tokens in the farm for a specific user
function lockedLiquidityOf(address account) external view returns (uint256) {
return _locked_liquidity[account];
}
/// @notice Total 'balance' used for calculating the percent of the pool the account owns
/// @return uint256 The combined weight. Takes into account the locked stake time multiplier and veFXS multiplier
function totalCombinedWeight() external view returns (uint256) {
return _total_combined_weight;
}
/// @notice Combined weight for a specific account
/// @return uint256 The combined weight.
function combinedWeightOf(address account) external view returns (uint256) {
return _combined_weights[account];
}
/// @notice All the locked stakes for a given account
/// @return LockedStake Array of LockedStakes
function lockedStakesOf(address account) external view returns (LockedStake[] memory) {
return lockedStakes[account];
}
/// @notice The lock multiplier for a given amount of seconds
/// @param secs Number of seconds you are locking
/// @return uint256 The lock multiplier
function lockMultiplier(uint256 secs) public view returns (uint256) {
return Math.min(
lock_max_multiplier,
(secs * lock_max_multiplier) / lock_time_for_max_multiplier
) ;
}
/// @notice The last time rewards were applicable. Should be the lesser of the current timestamp, or the end of the last period
/// @return uint256 The last timestamp where rewards were applicable
function lastTimeRewardApplicable() internal view returns (uint256) {
return Math.min(block.timestamp, periodFinish);
}
/// @notice How much Frax per 1 LP token
/// @return uint256 Amount of Frax
function fraxPerLPToken() public view returns (uint256) {
// Get the amount of FRAX 'inside' of the lp tokens
uint256 frax_per_lp_token;
// Balancer frxETH-bb-a-WETH Gauge
// ============================================
// {
// IBalancerVault vault = IBalancerVault(0xBA12222222228d8Ba445958a75a0704d566BF2C8);
// /**
// * `cash` is the number of tokens the Vault currently holds for the Pool. `managed` is the number of tokens
// * withdrawn and held outside the Vault by the Pool's token Asset Manager. The Pool's total balance for `token`
// * equals the sum of `cash` and `managed`.
// */
// (uint256 cash, uint256 managed, , ) = vault.getPoolTokenInfo(0xd00f9ca46ce0e4a63067c4657986f0167b0de1e5000000000000000000000b42, 0xEe327F889d5947c1dc1934Bb208a1E792F953E96);
// uint256 frxETH_usd_val_per_lp_e8 = ((cash + managed) * uint256(getLatestETHPriceE8())) / stakingToken.totalSupply();
// frax_per_lp_token = frxETH_usd_val_per_lp_e8 * (1e10); // We use USD as "Frax" here. Scale up to E18
// }
// Convex cvxLP/RewardPool Combo
// ============================================
// {
// // Half of the LP is FRAXBP. Half of that should be FRAX.
// // Using 0.25 * virtual price for gas savings
// ICurveChildLiquidityGauge gauge = ICurveChildLiquidityGauge(stakingToken.curveGauge());
// I3pool pool = I3pool(gauge.lp_token());
// frax_per_lp_token = pool.get_virtual_price() / 4;
// }
// Convex cvxfrxETH/XXXETH
// ============================================
// {
// // Get the pool
// ICurveChildLiquidityGauge gauge = ICurveChildLiquidityGauge(stakingToken.curveGauge());
// I2poolTokenNoLending pool = I2poolTokenNoLending(gauge.lp_token());
// // Assume frxETH = ETH for pricing purposes
// // Get the USD value of the frxETH per LP token
// uint256 frxETH_in_pool = IERC20(0x178412e79c25968a32e89b11f63B33F733770c2A).balanceOf(address(pool));
// uint256 frxETH_usd_val_per_lp_e8 = (frxETH_in_pool * uint256(getLatestETHPriceE8())) / pool.totalSupply();
// frax_per_lp_token = frxETH_usd_val_per_lp_e8 * (1e10); // We use USD as "Frax" here
// }
// Convex FRAX/FXB
// ============================================
// {
// // Count both FRAX and FXB as both are beneficial
// ICurveChildLiquidityGauge gauge = ICurveChildLiquidityGauge(stakingToken.curveGauge());
// ICurveStableSwapNG curvePool = ICurveStableSwapNG(gauge.lp_token());
// frax_per_lp_token = curvePool.get_virtual_price();
// }
// Curve 2-token (No Lending)
// ============================================
// {
// // Get the pool
// ICurveChildLiquidityGauge gauge = ICurveChildLiquidityGauge(stakingToken.curveGauge());
// I2poolTokenNoLending pool = I2poolTokenNoLending(gauge.lp_token());
// address coin0 = pool.coins(0);
// uint256 total_frax_reserves;
// uint256[2] memory _balanceResults = pool.get_balances();
// if (coin0 == fraxAddress) {
// total_frax_reserves = _balanceResults[0];
// }
// else {
// total_frax_reserves = _balanceResults[1];
// }
// frax_per_lp_token = total_frax_reserves.mul(1e18).div(pool.totalSupply());
// }
// Curve 3-token
// ============================================
// {
// address coin0 = stakingToken.coins(0);
// address coin1 = stakingToken.coins(1);
// uint256 total_frax_reserves;
// if (coin0 == fraxAddress) {
// total_frax_reserves = stakingToken.balances(0);
// }
// else if (coin1 == fraxAddress) {
// 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());
// }
// Curve 3pool metapool (FRAXBP/Stable)
// ============================================
// {
// // Half of the LP is FRAXBP. Half of that should be FRAX.
// // Using 0.25 * virtual price for gas savings
// frax_per_lp_token = stakingToken.get_virtual_price() / 4;
// }
// Fraxswap V2
// ============================================
{
uint256 total_frax_reserves;
// Technically getReserveAfterTwamm is more accurate, but if the TWAMM becomes paused, it will eventually gas out
// (uint256 _reserve0, uint256 _reserve1, , ,) = (stakingToken.getReserveAfterTwamm(block.timestamp));
(uint256 _reserve0, uint256 _reserve1, ) = (stakingToken.getReserves());
if (frax_is_token0) total_frax_reserves = _reserve0;
else total_frax_reserves = _reserve1;
frax_per_lp_token = (total_frax_reserves * 1e18) / stakingToken.totalSupply();
// Multiply by two since both sides (for FRAX/wfrxETH and FRAX/FXS) are beneficial to Frax
frax_per_lp_token *= 2;
}
// KyberSwap Elastic
// ============================================
// {
// // Fetch total pool TVL using the seed token id
// ComboOracle_KyberSwapElasticV2.NFTValueInfo memory nft_value_info = KSE_ComboOracleV2.getNFTValueInfo(seed_token_id);
// // Assume half of the liquidity is FRAX or FRAX-related, even if it is not.
// frax_per_lp_token = (nft_value_info.pool_tvl_usd * MULTIPLIER_PRECISION) / (stakingToken.totalSupply() * 2);
// }
// mStable
// ============================================
// {
// uint256 total_frax_reserves;
// (, IFeederPool.BassetData memory vaultData) = (stakingToken.getBasset(fraxAddress));
// 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(fraxAddress));
// 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(fraxAddress));
// frax_per_lp_token = total_frax.mul(1e18).div(stakingToken.totalSupply());
// }
// Sentiment LFrax
// ============================================
// {
// frax_per_lp_token = stakingToken.convertToAssets(1e18);
// }
// 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;
}
/// @notice Amount of Frax in the user's locked LP
/// @param account Address of the user
/// @return uint256 Amount of Frax
function userStakedFrax(address account) public view returns (uint256) {
return (fraxPerLPToken()).mul(_locked_liquidity[account]).div(1e18);
}
/// @notice Minimum amount of veFXS a user needs to have to get the max veFXS boost, given their current position
/// @param account Address of the user
/// @return uint256 Amount of veFXS needed
function minVeFXSForMaxBoost(address account) public view returns (uint256) {
return (userStakedFrax(account)).mul(vefxs_per_frax_for_max_boost).div(MULTIPLIER_PRECISION);
}
/// @notice The weight boost multiplier from veFXS
/// @param account Address of the user
/// @return uint256 The multiplier
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;
}
/// @notice The current lock multiplier, due to time, for a given stake. Decays with time
/// @param account Address of the user
/// @param stake_idx Index of the stake
/// @return midpoint_lock_multiplier The current lock multiplier
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;
}
/// @notice Calculate the combined weight for an account
/// @param account Address of the user
/// @return old_combined_weight The old combined weight for the user
/// @return new_vefxs_multiplier The new veFXS multiplier
/// @return new_combined_weight The new combined weight for the user
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;
}
}
/// @notice The calculated rewardPerTokenStored accumulator
/// @return _rtnRewardsPerTokenStored Array of rewardsPerTokenStored
function rewardPerToken() public view returns (uint256[] memory _rtnRewardsPerTokenStored) {
_rtnRewardsPerTokenStored = new uint256[](rewardTokens.length);
if (_total_liquidity_locked == 0 || _total_combined_weight == 0) {
_rtnRewardsPerTokenStored = rewardsPerTokenStored;
}
else {
// Loop through the reward tokens
for (uint256 i = 0; i < rewardTokens.length; i++) {
_rtnRewardsPerTokenStored[i] = rewardsPerTokenStored[i].add(
lastTimeRewardApplicable().sub(lastUpdateTime).mul(rewardRates[i]).mul(1e18).div(_total_combined_weight)
);
}
}
}
/// @notice The currently earned rewards for a user
/// @param account The staker's address
/// @return _rtnEarned Array of the amounts of reward tokens the staker can currently collect
function earned(address account) public view returns (uint256[] memory _rtnEarned) {
_rtnEarned = new uint256[](rewardTokens.length);
if (_combined_weights[account] == 0){
for (uint256 i = 0; i < rewardTokens.length; i++) {
_rtnEarned[i] = 0;
}
}
else {
uint256[] memory _rtnRewardsPerToken = rewardPerToken();
// Loop through the reward tokens
for (uint256 i = 0; i < rewardTokens.length; i++) {
_rtnEarned[i] = (_combined_weights[account].mul(_rtnRewardsPerToken[i].sub(userRewardsPerTokenPaid[account][i]))).div(1e18).add(rewards[account][i]);
}
}
}
/// @notice The duration (usually weekly) reward amounts for each token
/// @return _rtnRewardForDuration Array of the amounts of the reward tokens
function getRewardForDuration() external view returns (uint256[] memory _rtnRewardForDuration) {
_rtnRewardForDuration = new uint256[](rewardTokens.length);
for (uint256 i = 0; i < rewardTokens.length; i++) {
_rtnRewardForDuration[i] = rewardRates[i].mul(rewardsDuration);
}
}
/* ========== MUTATIVE FUNCTIONS ========== */
/// @notice Fetch a stake for a user
/// @param staker_address The address of the user
/// @param kek_id The kek_id of the stake
/// @return locked_stake The stake information, as a LockedStake
/// @return arr_idx The array index of the stake
function _getStake(address staker_address, bytes32 kek_id) internal view returns (LockedStake memory locked_stake, uint256 arr_idx) {
if (kek_id != 0) {
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(kek_id != 0 && locked_stake.kek_id == kek_id, "Stake not found");
}
/// @notice Update the reward and balance state for a staker
/// @param account The address of the user
/// @param sync_too If the non-user state should be synced too
/// @param pre_sync_vemxstored The pre-sync veFXS multiplier
function _updateRewardAndBalance(address account, bool sync_too, bool pre_sync_vemxstored) internal {
// Skip certain functions if we are in an emergency shutdown
if (!withdrawalOnlyShutdown) {
// Need to retro-adjust some things if the period hasn't been renewed, then start a new one
if (sync_too){
sync();
}
}
// Used to make sure the veFXS multiplier is correct if a stake is increased, before calcCurCombinedWeight
if (pre_sync_vemxstored){
_vefxsMultiplierStored[account] = veFXSMultiplier(account);
}
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
// Skip if we are in emergency shutdown
if (!withdrawalOnlyShutdown) _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);
}
}
}
/// @notice Add additional LPs to an existing locked stake. Also claims rewards at the old balance first
/// @param kek_id The kek_id of the stake
/// @param addl_liq The amount of additional liquidity to add
function lockAdditional(bytes32 kek_id, uint256 addl_liq) nonReentrant public {
// Make sure staking isn't paused
require(!stakingPaused, "Staking paused");
// Make sure you are not in shutdown
require(!withdrawalOnlyShutdown, "Only withdrawals allowed");
// Claim rewards at the old balance first
_getReward(msg.sender, msg.sender);
// 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, true);
emit LockedAdditional(msg.sender, kek_id, addl_liq);
}
/// @notice Extends the lock of an existing stake. Also claims rewards at the old balance first
/// @param kek_id The kek_id of the stake
/// @param new_ending_ts The new ending timestamp you want to extend to
function lockLonger(bytes32 kek_id, uint256 new_ending_ts) nonReentrant public {
// Make sure staking isn't paused
require(!stakingPaused, "Staking paused");
// Make sure you are not in shutdown
require(!withdrawalOnlyShutdown, "Only withdrawals allowed");
// Claim rewards at the old balance first
_getReward(msg.sender, msg.sender);
// 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, true);
emit LockedLonger(msg.sender, kek_id, new_secs, block.timestamp, new_ending_ts);
}
/// @notice Sync earnings for a specific staker
/// @param account The account to sync
function _syncEarned(address account) internal {
if (account != address(0)) {
// Calculate the earnings
uint256[] memory _earneds = earned(account);
for (uint256 i = 0; i < rewardTokens.length; i++) {
rewards[account][i] = _earneds[i];
userRewardsPerTokenPaid[account][i] = rewardsPerTokenStored[i];
}
}
}
/// @notice Staker can allow a migrator
/// @param migrator_address The address you want to add as a migrator. The contract owner would need to have approved this address first
function stakerAllowMigrator(address migrator_address) external {
require(valid_migrators[migrator_address], "Invalid migrator address");
staker_allowed_migrators[msg.sender][migrator_address] = true;
}
/// @notice Staker can disallow a migrator that they previously allowed
/// @param migrator_address The migrator address you want to disable
function stakerDisallowMigrator(address migrator_address) external {
// Delete from the mapping
delete staker_allowed_migrators[msg.sender][migrator_address];
}
/// @notice Lock LP tokens
/// @param liquidity The amount of LP tokens you want to stake
/// @param secs The length of time you want to lock
/// @dev 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);
}
/// @notice 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)
/// @param staker_address The address of the farmer
/// @param source_address The source of the LP tokens. Most of the time is the farmer, but could be the migrator
/// @param liquidity The amount of LP tokens you want to stake
/// @param secs The length of time you want to lock
/// @param start_timestamp The starting timestamp of the stake. Used by the migrator, otherwise it stays the same
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(!withdrawalOnlyShutdown, "Only withdrawals allowed");
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, true);
emit StakeLocked(staker_address, liquidity, secs, kek_id, source_address);
}
/// @notice Withdraw a stake.
/// @param kek_id The id for the stake
/// @param claim_rewards_deprecated DEPRECATED, has no effect (always claims rewards regardless)
/// @dev Two different withdrawLocked functions are needed because of delegateCall and msg.sender issues (important for migration)
function withdrawLocked(bytes32 kek_id, bool claim_rewards_deprecated) nonReentrant public {
require(withdrawalsPaused == false, "Withdrawals paused");
_withdrawLocked(msg.sender, msg.sender, kek_id, claim_rewards_deprecated);
}
/// @notice 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()
/// @param staker_address The address of the staker
/// @param destination_address Destination address for the withdrawn LP
/// @param kek_id The id for the stake
/// @param claim_rewards_deprecated DEPRECATED, has no effect (always claims rewards regardless)
function _withdrawLocked(address staker_address, address destination_address, bytes32 kek_id, bool claim_rewards_deprecated) internal {
// Collect rewards first and then update the balances
// withdrawalOnlyShutdown to be used in an emergency situation if reward is overemitted or not available
// and the user can forfeit rewards to get their principal back.
if (withdrawalOnlyShutdown) {
// Do nothing.
}
else {
// Get the rewards
_getReward(staker_address, destination_address);
}
(LockedStake memory thisStake, uint256 theArrayIndex) = _getStake(staker_address, kek_id);
require(block.timestamp >= thisStake.ending_timestamp || stakesUnlocked == true || valid_migrators[msg.sender] == true, "Stake is still locked!");
uint256 liquidity = thisStake.liquidity;
if (liquidity > 0) {
// Update liquidities
_total_liquidity_locked = _total_liquidity_locked.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, true, true);
// 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);
}
}
/// @notice Collect rewards
/// @return uint256 The amounts of collected reward tokens
/// @dev Two different getReward functions are needed because of delegateCall and msg.sender issues (important for migration)
function getReward() external nonReentrant returns (uint256[] memory) {
require(rewardsCollectionPaused == false,"Rewards collection paused");
return _getReward(msg.sender, msg.sender);
}
/// @notice Collect rewards (internal)
/// @param rewardee The address of the staker
/// @param destination_address Destination address for the withdrawn LP
/// @return _rtnRewards The amounts of collected reward tokens
/// @dev 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[] memory _rtnRewards) {
// Make sure you are not in shutdown
require(!withdrawalOnlyShutdown, "Only withdrawals allowed");
_rtnRewards = new uint256[](rewardTokens.length);
for (uint256 i = 0; i < rewardTokens.length; i++) {
_rtnRewards[i] = rewards[rewardee][i];
if (_rtnRewards[i] > 0) {
rewards[rewardee][i] = 0;
ERC20(rewardTokens[i]).transfer(destination_address, _rtnRewards[i]);
ttlRewsPaid[i] += _rtnRewards[i];
emit RewardPaid(rewardee, _rtnRewards[i], rewardTokens[i], destination_address);
}
}
// Update the last reward claim time
lastRewardClaimTime[rewardee] = block.timestamp;
}
/// @notice Quasi-notifyRewardAmount() logic
function syncRewards() internal {
// Bring in rewards, if applicable
if ((block.timestamp).sub(lastRewardPull) >= rewardsDuration) {
if (address(rewarder) != address(0)) {
rewarder.distributeReward();
}
// Pull in any 3rd party reward tokens, if applicable, using their specific ABI(s)
// FXS is always assumed to be at [0]
// for (uint256 i = 1; i < rewardTokens.length; i++) {
// if (rewardTokens[i] != address(0)) {
// }
// }
{
// Balancer
// =========================
// IL2BalancerPseudoMinter(0x47B489bf5836f83ABD928C316F8e39bC0587B020).mint(address(stakingToken));
// Convex cvxLP/RewardPool Combo
// =========================
// stakingToken.getReward(address(this));
}
lastRewardPull = block.timestamp;
}
// Loop through all the tokens
uint256 _eligibleElapsedTime = Math.min((block.timestamp).sub(lastUpdateTime), rewardsDuration); // Cut off at the end of the week
uint256[] memory _reward = rewardPerToken();
for (uint256 i = 0; i < rewardTokens.length; i++) {
// Get the current reward token balances
uint256 _currBal = ERC20(rewardTokens[i]).balanceOf(address(this));
// Update the owed amounts based off the old reward rates
// Anything over a week is zeroed (see above)
ttlRewsOwed[i] += rewardRates[i].mul(_eligibleElapsedTime);
// Update the stored amounts too
rewardsPerTokenStored[i] = _reward[i];
// Set the reward rates based on the free amount of tokens
{
// Don't count unpaid rewards as free
uint256 _unpaid = ttlRewsOwed[i].sub(ttlRewsPaid[i]);
// Handle reward token0
if (_currBal <= _unpaid){
// token is depleted, so stop emitting
rewardRates[i] = 0;
}
else {
uint256 _free = _currBal.sub(_unpaid);
rewardRates[i] = (_free).div(rewardsDuration);
}
}
}
}
/// @notice Sync the contract
function sync() public {
require(isInitialized, "Contract not initialized");
// Make sure you are not in shutdown
require(!withdrawalOnlyShutdown, "Only withdrawals allowed");
// Make sure the rewardRates are synced to the current reward token balances
syncRewards();
// Rolling 7 days rewards period
lastUpdateTime = block.timestamp;
periodFinish = (block.timestamp).add(rewardsDuration);
}
/* ========== RESTRICTED FUNCTIONS ========== */
/// @notice Needed when first deploying the farm, Make sure rewards are present
function initializeDefault() external onlyByOwnGovCtrlr {
require(!isInitialized, "Already initialized");
isInitialized = true;
// Sync the contract
sync();
emit DefaultInitialization();
}
/// @notice Migrator can stake for someone else (they won't be able to withdraw it back though, only staker_address can).
/// @param staker_address The address of the staker
/// @param amount Amount of LP to stake
/// @param secs Seconds for the lock
/// @param start_timestamp Starting timestamp for the lock
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);
}
/// @notice Migrator can withdraw for someone else
/// @param staker_address The address of the staker
/// @param kek_id The id of the stake
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, true);
}
/// @notice Adds a supported migrator address
/// @param migrator_address The address of the migrator
function addMigrator(address migrator_address) external onlyByOwnGov {
valid_migrators[migrator_address] = true;
}
/// @notice Removes a migrator address
/// @param migrator_address The address of the migrator
function removeMigrator(address migrator_address) external onlyByOwnGov {
require(valid_migrators[migrator_address] == true, "Address nonexistent");
// Delete from the mapping
delete valid_migrators[migrator_address];
}
/// @notice Added to support recovering LP Rewards and other mistaken tokens from other systems to be distributed to holders
/// @param tokenAddress The address of the token
/// @param tokenAmount The amount of the token
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);
}
/// @notice Set various multipliers
/// @param _lock_max_multiplier The max weight multiplier you can get for locking your position
/// @param _vefxs_max_multiplier The max weight multiplier you can get for having veFXS
/// @param _vefxs_per_frax_for_max_boost How much veFXS you must have, per Frax in the LP, in order to get the veFXS boost, if applicable
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);
}
/// @notice Set various time variables
/// @param _lock_time_for_max_multiplier The lock time needed to get the max weight multiplier
/// @param _lock_time_min The minimum lock time required
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);
}
/// @notice Unlock all stakes, in the case of an emergency
function unlockStakes() external onlyByOwnGov {
stakesUnlocked = !stakesUnlocked;
}
/// @notice Toggle migrations on or off
function toggleMigrations() external onlyByOwnGov {
migrationsOn = !migrationsOn;
}
/// @notice Only settable to true
function initiateWithdrawalOnlyShutdown() external onlyByOwnGov {
withdrawalOnlyShutdown = true;
}
/// @notice Toggle the ability to stake
function toggleStaking() external onlyByOwnGov {
stakingPaused = !stakingPaused;
}
/// @notice Toggle the ability to withdraw
function toggleWithdrawals() external onlyByOwnGov {
withdrawalsPaused = !withdrawalsPaused;
}
/// @notice Toggle the ability to collect rewards
function toggleRewardsCollection() external onlyByOwnGov {
rewardsCollectionPaused = !rewardsCollectionPaused;
}
/// @notice Set the address of the timelock
/// @param _new_timelock The new address of the timelock
function setTimelock(address _new_timelock) external onlyByOwnGov {
timelockAddress = _new_timelock;
}
/// @notice Set the address of the controller
/// @param _controllerAddress The new address of the controller
function setController(address _controllerAddress) external onlyByOwnGov {
controllerAddress = _controllerAddress;
}
/// @notice Set the veFXS address
/// @param _vefxs_address The new address for veFXS
function setVeFXS(address _vefxs_address) external onlyByOwnGov {
veFXS = IveFXS(_vefxs_address);
}
/* ========== EVENTS ========== */
/// @notice When LP tokens are locked
/// @param user The staker
/// @param amount Amount of LP staked
/// @param secs Number of seconds the stake was locked
/// @param kek_id The id of the stake
/// @param source_address The origin address of the LP tokens. Usually the same as the user unless there is a migration in progress
event StakeLocked(address indexed user, uint256 amount, uint256 secs, bytes32 kek_id, address source_address);
/// @notice When LP tokens are withdrawn
/// @param user The staker
/// @param amount Amount of LP withdrawn
/// @param kek_id The id of the stake
/// @param destination_address Destination address of the withdrawn LP tokens
event WithdrawLocked(address indexed user, uint256 amount, bytes32 kek_id, address destination_address);
/// @notice When a staker collects rewards
/// @param user The staker
/// @param reward Amount of reward tokens
/// @param token_address Address of the reward token
/// @param destination_address Destination address of the reward tokens
event RewardPaid(address indexed user, uint256 reward, address token_address, address destination_address);
/// @notice When the farm has been initialized
event DefaultInitialization();
/// @notice When tokens are recovered, in the case of an emergency
/// @param token Address of the token
/// @param amount Amount of the recovered tokens
event Recovered(address token, uint256 amount);
/// @notice When the max weight multiplier you can get for locking your position is set
/// @param multiplier The max weight multiplier
event LockedStakeMaxMultiplierUpdated(uint256 multiplier);
/// @notice When the lock time needed to get the max weight multiplier is set
/// @param secs The lock time needed for the max multiplier, in seconds
event LockedStakeTimeForMaxMultiplier(uint256 secs);
/// @notice The minimum lock time required for a stake
/// @param secs Min lock time, in seconds
event LockedStakeMinTime(uint256 secs);
/// @notice When someone adds additional LP to an existing stake
/// @param user The staker's address
/// @param kek_id The id of the stake
/// @param amount The amount of extra LP being added to the stake
event LockedAdditional(address indexed user, bytes32 kek_id, uint256 amount);
/// @notice When someone locks for additional time
/// @param user The staker's address
/// @param kek_id The id of the stake
/// @param new_secs The additional amount of seconds the lock is being extended
/// @param new_start_ts The new start time of the stake. Should be block.timestamp
/// @param new_end_ts The new ending time of the stake
event LockedLonger(address indexed user, bytes32 kek_id, uint256 new_secs, uint256 new_start_ts, uint256 new_end_ts);
/// @notice When the max weight multiplier you can get for having veFXS is updated
/// @param multiplier The new max multiplier
event MaxVeFXSMultiplier(uint256 multiplier);
/// @notice When the amount of veFXS you must have, per Frax in the LP, in order to get the veFXS boost, if applicable
/// @param scale_factor The new amount of veFXS
event veFXSPerFraxForMaxBoostUpdated(uint256 scale_factor);
}
// File contracts/Staking/Variants/FraxCCFarmV4_cvxLP.sol
// Original license: SPDX_License_Identifier: GPL-2.0-or-later
contract FraxCCFarmV4_cvxLP is FraxCrossChainFarmV4_ERC20 {
string public farm_type = "FraxCCFarmV4_cvxLP";
constructor (
address _owner,
address[] memory _rewardTokens,
address _stakingToken,
address _fraxAddress,
address _timelockAddress,
address _rewarder_address
)
FraxCrossChainFarmV4_ERC20(_owner, _rewardTokens, _stakingToken, _fraxAddress, _timelockAddress, _rewarder_address)
{}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address[]","name":"_rewardTokens","type":"address[]"},{"internalType":"address","name":"_stakingToken","type":"address"},{"internalType":"address","name":"_fraxAddress","type":"address"},{"internalType":"address","name":"_timelockAddress","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":"controllerAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"earned","outputs":[{"internalType":"uint256[]","name":"_rtnEarned","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"farm_type","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"fraxAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"fraxPerLPToken","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getReward","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getRewardForDuration","outputs":[{"internalType":"uint256[]","name":"_rtnRewardForDuration","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"initializeDefault","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"initiateWithdrawalOnlyShutdown","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 FraxCrossChainFarmV4_ERC20.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":"_rtnRewardsPerTokenStored","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"rewardRates","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"rewardTokenAddrToIdx","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"rewardTokens","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rewarder","outputs":[{"internalType":"contract FraxCrossChainRewarder","name":"","type":"address"}],"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":[{"internalType":"address","name":"_controllerAddress","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 IFraxswapPair","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"sync","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"timelockAddress","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":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"ttlRewsOwed","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"ttlRewsPaid","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unlockStakes","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"userStakedFrax","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","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":[],"name":"version","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"kek_id","type":"bytes32"},{"internalType":"bool","name":"claim_rewards_deprecated","type":"bool"}],"name":"withdrawLocked","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"withdrawalOnlyShutdown","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"withdrawalsPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}]Contract Creation Code
6729a2241af62c0000600c556305a39a80600d556001600e55673782dace9d900000600f55671bc16d674ec8000060105562093a8060155560c06040526005608090815264302e302e3960d81b60a0526026906200005e9082620005c8565b5060408051808201909152601281527104672617843434661726d56345f6376784c560741b6020820152602790620000979082620005c8565b50348015620000a557600080fd5b5060405162005f4338038062005f43833981016040819052620000c891620006b1565b858585858585856001600160a01b0381166200012b5760405162461bcd60e51b815260206004820152601960248201527f4f776e657220616464726573732063616e6e6f7420626520300000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b03831690811782556040805192835260208301919091527fb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159c910160405180910390a1506001600255600780546001600160a01b0319166001600160a01b0385161790558451620001b8906004906020880190620004a0565b5060005b855181101562000324578060146000888481518110620001e057620001e0620007e3565b60200260200101516001600160a01b03166001600160a01b0316815260200190815260200160002081905550600160136000888481518110620002275762000227620007e3565b6020908102919091018101516001600160a01b031682528101919091526040016000908120805460ff1916921515929092179091556018805460018181019092557fb13d2d76d1f4b7be834882e410b3e3a8afaf69f83600ae24db354391d2378d2e01829055601680548083019091557fd833147d7dc355ba459fc788f669e58cfaf9dc25ddcd0702e87d69c7b512428901829055601780548083019091557fc624b66cc0138b8fabc209247f72d758e1cf3343756d543badbf24212bed8c15018290556012805480830182559083527fbb8a6a4669ba250d26cd7a459eca9d215f8307e33aebe50379bc5a3617ec3444019190915501620001bc565b50600580546001600160a01b038087166001600160a01b0319928316811790935560088054868316908416179055600680549185169190921617905560408051630dfe168160e01b8152905160009291630dfe16819160048083019260209291908290030181865afa1580156200039f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620003c59190620007f9565b6007549091506001600160a01b0390811690821603620003f2576021805460ff19166001179055620003fd565b6021805460ff191690555b6025805461ffff1916905542600b8190556015546200041d919062000434565b600a5550620008409b505050505050505050505050565b6000806200044383856200081e565b905083811015620004975760405162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015260640162000122565b90505b92915050565b828054828255906000526020600020908101928215620004f8579160200282015b82811115620004f857825182546001600160a01b0319166001600160a01b03909116178255602090920191600190910190620004c1565b50620005069291506200050a565b5090565b5b808211156200050657600081556001016200050b565b634e487b7160e01b600052604160045260246000fd5b600181811c908216806200054c57607f821691505b6020821081036200056d57634e487b7160e01b600052602260045260246000fd5b50919050565b601f821115620005c3576000816000526020600020601f850160051c810160208610156200059e5750805b601f850160051c820191505b81811015620005bf57828155600101620005aa565b5050505b505050565b81516001600160401b03811115620005e457620005e462000521565b620005fc81620005f5845462000537565b8462000573565b602080601f8311600181146200063457600084156200061b5750858301515b600019600386901b1c1916600185901b178555620005bf565b600085815260208120601f198616915b82811015620006655788860151825594840194600190910190840162000644565b5085821015620006845787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b80516001600160a01b0381168114620006ac57600080fd5b919050565b60008060008060008060c08789031215620006cb57600080fd5b620006d68762000694565b602088810151919750906001600160401b0380821115620006f657600080fd5b818a0191508a601f8301126200070b57600080fd5b81518181111562000720576200072062000521565b8060051b604051601f19603f8301168101818110858211171562000748576200074862000521565b60405291825284820192508381018501918d8311156200076757600080fd5b938501935b828510156200079057620007808562000694565b845293850193928501926200076c565b809a50505050505050620007a76040880162000694565b9350620007b76060880162000694565b9250620007c76080880162000694565b9150620007d760a0880162000694565b90509295509295509295565b634e487b7160e01b600052603260045260246000fd5b6000602082840312156200080c57600080fd5b620008178262000694565b9392505050565b808201808211156200049a57634e487b7160e01b600052601160045260246000fd5b6156f380620008506000396000f3fe608060405234801561001057600080fd5b50600436106105135760003560e01c80637bb7bed1116102a1578063cd3daf9d1161016b578063e9f2838e116100e3578063f288baf611610097578063f2caeb1e1161007c578063f2caeb1e14610b73578063fce6fd1314610b86578063fff6cae914610b9357600080fd5b8063f288baf614610b61578063f2a8d34914610b6a57600080fd5b8063ebe2b12b116100c8578063ebe2b12b14610b22578063ee89e02f14610b2b578063f12f144714610b4e57600080fd5b8063e9f2838e14610afc578063eb3c209e14610b0f57600080fd5b8063d42fc9b41161013a578063dcc3e06e1161011f578063dcc3e06e14610acc578063e01f62bf14610aec578063e1ba95d214610af457600080fd5b8063d42fc9b414610a83578063d9f96e8d14610a9657600080fd5b8063cd3daf9d14610a57578063cdc82e8014610a5f578063d239f00314610a68578063d2fbdc0d14610a7057600080fd5b80639b8c15a811610219578063b85efd06116101cd578063bbb781cc116101b2578063bbb781cc14610a26578063bdacb30314610a3b578063c8f33c9114610a4e57600080fd5b8063b85efd0614610a0a578063b94c4dcb14610a1d57600080fd5b8063a2217bc5116101fe578063a2217bc5146109dc578063a65fd70a146109e4578063af00f4e2146109f757600080fd5b80639b8c15a81461099b5780639c5303eb146109c957600080fd5b80638bad86a711610270578063903bd2af11610255578063903bd2af1461096357806392eefe9b146109765780639637927f1461098957600080fd5b80638bad86a7146109155780638da5cb5b1461094357600080fd5b80637bb7bed1146108c6578063818a2ba6146108d95780638980f11f146108ec57806389b5f00b146108ff57600080fd5b806341edbdf0116103e25780636885d3161161035a57806372f702f31161030e5780637970833e116102f35780637970833e1461087b57806379ba5097146108b65780637b31c19a146108be57600080fd5b806372f702f314610848578063774d4ae71461086857600080fd5b80636ce46bc31161033f5780636ce46bc3146108235780636cea0b0d146108365780636e27cef91461083f57600080fd5b80636885d316146107fb578063693392451461080357600080fd5b806352732bc8116103b157806354fd4d501161039657806354fd4d50146107e35780635bfd9258146107eb57806364f2c060146107f357600080fd5b806352732bc81461075c57806353a47bb7146107c357600080fd5b806341edbdf0146106f45780634b24ea47146107095780634bc66f32146107295780634fd2b5361461074957600080fd5b80631c1f78eb1161049057806336f89af211610444578063392e53cd11610429578063392e53cd146106cd5780633b8105b3146106e45780633d18b912146106ec57600080fd5b806336f89af21461068f578063386a9525146106c457600080fd5b806328ef934e1161047557806328ef934e146106455780632c0c2a0a14610658578063323331ca1461066b57600080fd5b80631c1f78eb1461061d5780631e090f011461062557600080fd5b8063169d27ef116104e757806317b18c89116104cc57806317b18c89146105d757806319ff52fd146105ea5780631b3e870a1461060a57600080fd5b8063169d27ef1461058a578063174ed0ca1461059257600080fd5b80628cc26214610518578063046e7d3f146105415780630d7bac4f146105565780631627540c14610577575b600080fd5b61052b61052636600461522e565b610b9b565b6040516105389190615249565b60405180910390f35b61055461054f36600461522e565b610d51565b005b61056961056436600461528d565b610e40565b604051908152602001610538565b61055461058536600461522e565b610e6c565b610554610f8c565b6007546105b29073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610538565b6105546105e53660046152a6565b61112c565b6003546105b29073ffffffffffffffffffffffffffffffffffffffff1681565b61055461061836600461522e565b6111b1565b61052b611334565b61063861063336600461522e565b6113e6565b60405161053891906152c8565b610554610653366004615336565b61149a565b61056961066636600461522e565b6115d3565b60255461067f906301000000900460ff1681565b6040519015158152602001610538565b61056961069d36600461522e565b73ffffffffffffffffffffffffffffffffffffffff16600090815260208052604090205490565b61056960155481565b60255461067f906601000000000000900460ff1681565b610554611706565b61052b6117e6565b6106fc6118df565b6040516105389190615393565b6009546105b29073ffffffffffffffffffffffffffffffffffffffff1681565b6008546105b29073ffffffffffffffffffffffffffffffffffffffff1681565b61056961075736600461522e565b61196d565b61055461076a36600461522e565b33600090815260246020908152604080832073ffffffffffffffffffffffffffffffffffffffff9490941683529290522080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055565b6001546105b29073ffffffffffffffffffffffffffffffffffffffff1681565b6106fc61198a565b610569611997565b601e54610569565b610554611b23565b61056961081136600461522e565b60146020526000908152604090205481565b6105546108313660046153e4565b611bf8565b610569601b5481565b610569600e5481565b6005546105b29073ffffffffffffffffffffffffffffffffffffffff1681565b610569610876366004615410565b611e59565b61088e610889366004615410565b612065565b604080519586526020860194909452928401919091526060830152608082015260a001610538565b6105546120b3565b6105546121fe565b6105b26108d436600461528d565b6122dd565b6105696108e736600461528d565b612314565b6105546108fa366004615410565b612335565b60255461067f9065010000000000900460ff1681565b61092861092336600461522e565b612559565b60408051938452602084019290925290820152606001610538565b6000546105b29073ffffffffffffffffffffffffffffffffffffffff1681565b610554610971366004615448565b612784565b61055461098436600461522e565b612872565b60255461067f90610100900460ff1681565b61067f6109a9366004615478565b602460209081526000928352604080842090915290825290205460ff1681565b6105546109d736600461522e565b61295c565b610554612a4e565b6105696109f236600461528d565b612b23565b610554610a053660046152a6565b612b33565b610554610a183660046152a6565b612d19565b610569600d5481565b60255461067f90640100000000900460ff1681565b610554610a4936600461522e565b612fed565b610569600b5481565b61052b6130d7565b610569600c5481565b610554613235565b610554610a7e3660046152a6565b613313565b610569610a9136600461522e565b613760565b610569610aa436600461522e565b73ffffffffffffffffffffffffffffffffffffffff166000908152601f602052604090205490565b6006546105b29073ffffffffffffffffffffffffffffffffffffffff1681565b601d54610569565b6105546137a0565b60255461067f9062010000900460ff1681565b610554610b1d366004615410565b61387d565b610569600a5481565b61067f610b3936600461522e565b60236020526000908152604090205460ff1681565b610554610b5c36600461522e565b6139b4565b61056960105481565b610569600f5481565b610569610b8136600461528d565b613a9f565b60255461067f9060ff1681565b610554613aaf565b60045460609067ffffffffffffffff811115610bb957610bb96154ab565b604051908082528060200260200182016040528015610be2578160200160208202803683370190505b5073ffffffffffffffffffffffffffffffffffffffff8316600090815260208052604081205491925003610c4a5760005b600454811015610c44576000828281518110610c3157610c316154da565b6020908102919091010152600101610c13565b50919050565b6000610c546130d7565b905060005b600454811015610d495773ffffffffffffffffffffffffffffffffffffffff84166000818152601a60209081526040808320858452825280832054938352601982528083208584529091529020548351610d249291610d1e91670de0b6b3a764000091610d1891610ced9190899089908110610cd757610cd76154da565b6020026020010151613bbb90919063ffffffff16565b73ffffffffffffffffffffffffffffffffffffffff8a16600090815260208052604090205490613c04565b90613cbc565b90613cfe565b838281518110610d3657610d366154da565b6020908102919091010152600101610c59565b50505b919050565b60005473ffffffffffffffffffffffffffffffffffffffff16331480610d8e575060085473ffffffffffffffffffffffffffffffffffffffff1633145b610df9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b000000000000000000000060448201526064015b60405180910390fd5b600380547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b600c54600d54600091610e6691610e578286615538565b610e61919061554f565b613d77565b92915050565b60005473ffffffffffffffffffffffffffffffffffffffff163314610f13576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602f60248201527f4f6e6c792074686520636f6e7472616374206f776e6572206d6179207065726660448201527f6f726d207468697320616374696f6e00000000000000000000000000000000006064820152608401610df0565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040519081527f906a1c6bd7e3091ea86693dd029a831c19049ce77f1dce2ce0bab1cacbabce229060200160405180910390a150565b60005473ffffffffffffffffffffffffffffffffffffffff16331480610fc9575060085473ffffffffffffffffffffffffffffffffffffffff1633145b80610feb575060095473ffffffffffffffffffffffffffffffffffffffff1633145b611051576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4e6f74206f776e2c20746c6b2c206f72206374726c72000000000000000000006044820152606401610df0565b6025546601000000000000900460ff16156110c8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f416c726561647920696e697469616c697a6564000000000000000000000000006044820152606401610df0565b602580547fffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffff166601000000000000179055611101613aaf565b6040517fb5cfe3ccd03847076864f081609024cbc2eb98c38da4d8b2cebe9479a9a1ef3790600090a1565b6002805403611197576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610df0565b600280556111a83380848442613d8d565b50506001600255565b60005473ffffffffffffffffffffffffffffffffffffffff163314806111ee575060085473ffffffffffffffffffffffffffffffffffffffff1633145b611254576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b00000000000000000000006044820152606401610df0565b73ffffffffffffffffffffffffffffffffffffffff811660009081526023602052604090205460ff1615156001146112e8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f41646472657373206e6f6e6578697374656e74000000000000000000000000006044820152606401610df0565b73ffffffffffffffffffffffffffffffffffffffff16600090815260236020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055565b60045460609067ffffffffffffffff811115611352576113526154ab565b60405190808252806020026020018201604052801561137b578160200160208202803683370190505b50905060005b6004548110156113e2576113bd601554601283815481106113a4576113a46154da565b9060005260206000200154613c0490919063ffffffff16565b8282815181106113cf576113cf6154da565b6020908102919091010152600101611381565b5090565b73ffffffffffffffffffffffffffffffffffffffff81166000908152602260209081526040808320805482518185028101850190935280835260609492939192909184015b8282101561148f57838290600052602060002090600502016040518060a0016040529081600082015481526020016001820154815260200160028201548152602001600382015481526020016004820154815250508152602001906001019061142b565b505050509050919050565b60255460ff16151560011461150b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f4e6f7420696e206d6967726174696f6e000000000000000000000000000000006044820152606401610df0565b73ffffffffffffffffffffffffffffffffffffffff8416600090815260246020908152604080832033845290915290205460ff16801561155a57503360009081526023602052604090205460ff165b6115c0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f4d69672e20696e76616c6964206f7220756e617070726f7665640000000000006044820152606401610df0565b6115cd8433858585613d8d565b50505050565b60035460009073ffffffffffffffffffffffffffffffffffffffff16156116fe5760006115ff8361196d565b905080156116f5576003546040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85811660048301526000926116b7928592610d1892670de0b6b3a7640000929116906370a0823190602401602060405180830381865afa15801561168d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116b1919061558a565b90613c04565b905060006116dc670de0b6b3a7640000610d1860105485613c0490919063ffffffff16565b90506010548111156116ed57506010545b949350505050565b50600092915050565b506000919050565b60005473ffffffffffffffffffffffffffffffffffffffff16331480611743575060085473ffffffffffffffffffffffffffffffffffffffff1633145b6117a9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b00000000000000000000006044820152606401610df0565b602580547fffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffff81166401000000009182900460ff1615909102179055565b60606002805403611853576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610df0565b600280556025546301000000900460ff16156118cb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f5265776172647320636f6c6c656374696f6e20706175736564000000000000006044820152606401610df0565b6118d5333361423f565b9050600160025590565b602780546118ec906155a3565b80601f0160208091040260200160405190810160405280929190818152602001828054611918906155a3565b80156119655780601f1061193a57610100808354040283529160200191611965565b820191906000526020600020905b81548152906001019060200180831161194857829003601f168201915b505050505081565b6000610e66670de0b6b3a7640000610d18600f546116b186613760565b602680546118ec906155a3565b6000806000806000600560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16630902f1ac6040518163ffffffff1660e01b8152600401606060405180830381865afa158015611a0c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a30919061560e565b506021546dffffffffffffffffffffffffffff92831694509116915060ff1615611a5c57819250611a60565b8092505b600560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611acd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611af1919061558a565b611b0384670de0b6b3a7640000615538565b611b0d919061554f565b9350611b1a600285615538565b95945050505050565b60005473ffffffffffffffffffffffffffffffffffffffff16331480611b60575060085473ffffffffffffffffffffffffffffffffffffffff1633145b611bc6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b00000000000000000000006044820152606401610df0565b602580547fffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffffff1665010000000000179055565b60005473ffffffffffffffffffffffffffffffffffffffff16331480611c35575060085473ffffffffffffffffffffffffffffffffffffffff1633145b611c9b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b00000000000000000000006044820152606401610df0565b670de0b6b3a7640000831015611d32576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f4d756c74206d757374206265203e3d204d554c5449504c4945525f505245434960448201527f53494f4e000000000000000000000000000000000000000000000000000000006064820152608401610df0565b60008111611d9c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f766546585320706374206d6178206d757374206265203e3d20300000000000006044820152606401610df0565b600c8390556010829055600f8190556040518281527fc9d56ccdd6b954d8d74700db074cc667054f8e33c1b8d23e97021d4c588a87619060200160405180910390a17fa1676084a9eea08c6f205b60799323b364a1bd8e10aba89f0fbd94cfbf68b5dd600c54604051611e1191815260200190565b60405180910390a17f58c7ececaeb4704a0039e0d22c1b618367f7a7b9a4e191ab9baed34898f63f2e600f54604051611e4c91815260200190565b60405180910390a1505050565b73ffffffffffffffffffffffffffffffffffffffff82166000908152602260205260408120805482919084908110611e9357611e936154da565b600091825260208083206040805160a081018252600590940290910180548452600181015484840181905260028201548584015260038201546060860152600490910154608085015273ffffffffffffffffffffffffffffffffffffffff89168552601c9092528320549193501115611f1157506020810151611f39565b5073ffffffffffffffffffffffffffffffffffffffff84166000908152601c60205260409020545b42826060015111611ff957606082015173ffffffffffffffffffffffffffffffffffffffff86166000908152601c60205260409020541015611ff0576000818360600151611f87919061565e565b90506000836060015142611f9b919061565e565b90506000611fad61056460028561554f565b90506000611fbb8382615538565b611fc58584615538565b611fcf9190615671565b9050611fdb8385615671565b611fe5908261554f565b965050505050612049565b60009250612049565b60008082846060015161200c919061565e565b90506000428560600151612020919061565e565b9050600261202e8284615671565b612038919061554f565b9250505061204581610e40565b9350505b816080015183111561205d57816080015192505b505092915050565b6022602052816000526040600020818154811061208157600080fd5b600091825260209091206005909102018054600182015460028301546003840154600490940154929550909350919085565b60015473ffffffffffffffffffffffffffffffffffffffff16331461215a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603560248201527f596f75206d757374206265206e6f6d696e61746564206265666f726520796f7560448201527f2063616e20616363657074206f776e65727368697000000000000000000000006064820152608401610df0565b6000546001546040805173ffffffffffffffffffffffffffffffffffffffff93841681529290911660208301527fb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159c910160405180910390a160018054600080547fffffffffffffffffffffffff000000000000000000000000000000000000000090811673ffffffffffffffffffffffffffffffffffffffff841617909155169055565b60005473ffffffffffffffffffffffffffffffffffffffff1633148061223b575060085473ffffffffffffffffffffffffffffffffffffffff1633145b6122a1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b00000000000000000000006044820152606401610df0565b602580547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffff811663010000009182900460ff1615909102179055565b600481815481106122ed57600080fd5b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff16905081565b6017818154811061232457600080fd5b600091825260209091200154905081565b60005473ffffffffffffffffffffffffffffffffffffffff16331480612372575060085473ffffffffffffffffffffffffffffffffffffffff1633145b6123d8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b00000000000000000000006044820152606401610df0565b60255460ff166124675760055473ffffffffffffffffffffffffffffffffffffffff90811690831603612467576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f4e6f7420696e206d6967726174696f6e000000000000000000000000000000006044820152606401610df0565b6000546040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9182166004820152602481018390529083169063a9059cbb906044016020604051808303816000875af11580156124e0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125049190615684565b506040805173ffffffffffffffffffffffffffffffffffffffff84168152602081018390527f8c1256b8896378cd5044f80c202f9772b9d77dc85c8a6eb51967210b09bfaa2891015b60405180910390a15050565b73ffffffffffffffffffffffffffffffffffffffff811660009081526020805260408120549080612589846115d3565b73ffffffffffffffffffffffffffffffffffffffff85166000908152601f6020526040812054919350901580156125e2575073ffffffffffffffffffffffffffffffffffffffff85166000908152602080526040902054155b80612612575073ffffffffffffffffffffffffffffffffffffffff85166000908152601160205260409020548310155b1561261e57508161265e565b73ffffffffffffffffffffffffffffffffffffffff85166000908152601160205260409020546002906126519085615671565b61265b919061554f565b90505b6000915060005b73ffffffffffffffffffffffffffffffffffffffff861660009081526022602052604090205481101561277b5773ffffffffffffffffffffffffffffffffffffffff861660009081526022602052604081208054839081106126c9576126c96154da565b90600052602060002090600502016040518060a001604052908160008201548152602001600182015481526020016002820154815260200160038201548152602001600482015481525050905060006127228884611e59565b60408301519091506000670de0b6b3a764000061273f8785615671565b6127499084615538565b612753919061554f565b61275d9083615671565b90506127698188615671565b96505060019093019250612665915050565b50509193909250565b60028054036127ef576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610df0565b6002805560255462010000900460ff1615612866576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f5769746864726177616c732070617573656400000000000000000000000000006044820152606401610df0565b6111a8333384846145e4565b60005473ffffffffffffffffffffffffffffffffffffffff163314806128af575060085473ffffffffffffffffffffffffffffffffffffffff1633145b612915576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b00000000000000000000006044820152606401610df0565b600980547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b60005473ffffffffffffffffffffffffffffffffffffffff16331480612999575060085473ffffffffffffffffffffffffffffffffffffffff1633145b6129ff576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b00000000000000000000006044820152606401610df0565b73ffffffffffffffffffffffffffffffffffffffff16600090815260236020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b60005473ffffffffffffffffffffffffffffffffffffffff16331480612a8b575060085473ffffffffffffffffffffffffffffffffffffffff1633145b612af1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b00000000000000000000006044820152606401610df0565b602580547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00811660ff90911615179055565b6016818154811061232457600080fd5b60005473ffffffffffffffffffffffffffffffffffffffff16331480612b70575060085473ffffffffffffffffffffffffffffffffffffffff1633145b612bd6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b00000000000000000000006044820152606401610df0565b6001821015612c41576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f4d756c206d61782074696d65206d757374206265203e3d2031000000000000006044820152606401610df0565b6001811015612cac576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f4d756c206d696e2074696d65206d757374206265203e3d2031000000000000006044820152606401610df0565b600d829055600e8190556040518281527f0e3e3fae480c6f92291358a02bc83f04ee1971d5488596bffda7929d57ab470f9060200160405180910390a16040518181527f0534d208d75dfdbfacc1204745dd9b3c4c37e8cfc05eb5e8e3ae538aedb0a9fa9060200161254d565b6002805403612d84576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610df0565b60028055602554640100000000900460ff1615612dfd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f5374616b696e67207061757365640000000000000000000000000000000000006044820152606401610df0565b60255465010000000000900460ff1615612e73576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f4f6e6c79207769746864726177616c7320616c6c6f77656400000000000000006044820152606401610df0565b612e7d333361423f565b50600080612e8b338561488e565b915091506000838360400151612ea19190615671565b9050600554612ec89073ffffffffffffffffffffffffffffffffffffffff16333087614a5c565b6040805160a081018252868152602085810151818301528183018490526060808701519083015260808087015190830152336000908152602290915291909120805484908110612f1a57612f1a6154da565b9060005260206000209060050201600082015181600001556020820151816001015560408201518160020155606082015181600301556080820151816004015590505083601d6000828254612f6f9190615671565b9091555050336000908152601f602052604081208054869290612f93908490615671565b90915550612fa690503360006001614bfa565b604080518681526020810186905233917f2640b32e7e5d0fa2a21ea06b22fbd75fda0fda384a895a5fdeef43646de47a0c910160405180910390a250506001600255505050565b60005473ffffffffffffffffffffffffffffffffffffffff1633148061302a575060085473ffffffffffffffffffffffffffffffffffffffff1633145b613090576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b00000000000000000000006044820152606401610df0565b600880547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b60045460609067ffffffffffffffff8111156130f5576130f56154ab565b60405190808252806020026020018201604052801561311e578160200160208202803683370190505b509050601d54600014806131325750601e54155b1561318d57601880548060200260200160405190810160405280929190818152602001828054801561318357602002820191906000526020600020905b81548152602001906001019080831161316f575b5050505050905090565b60005b6004548110156113e2576132106131e4601e54610d18670de0b6b3a76400006116b1601287815481106131c5576131c56154da565b90600052602060002001546116b1600b546131de614d7a565b90613bbb565b601883815481106131f7576131f76154da565b9060005260206000200154613cfe90919063ffffffff16565b828281518110613222576132226154da565b6020908102919091010152600101613190565b60005473ffffffffffffffffffffffffffffffffffffffff16331480613272575060085473ffffffffffffffffffffffffffffffffffffffff1633145b6132d8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b00000000000000000000006044820152606401610df0565b602580547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffff8116620100009182900460ff1615909102179055565b600280540361337e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610df0565b60028055602554640100000000900460ff16156133f7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f5374616b696e67207061757365640000000000000000000000000000000000006044820152606401610df0565b60255465010000000000900460ff161561346d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f4f6e6c79207769746864726177616c7320616c6c6f77656400000000000000006044820152606401610df0565b613477333361423f565b50600080613485338561488e565b915091504283116134f2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4d75737420626520696e207468652066757475726500000000000000000000006044820152606401610df0565b600042836060015111613506576000613516565b428360600151613516919061565e565b90506000613524428661565e565b905081811161358f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f43616e6e6f742073686f7274656e206c6f636b2074696d6500000000000000006044820152606401610df0565b600e548110156135fb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f4d696e696d756d207374616b652074696d65206e6f74206d65740000000000006044820152606401610df0565b600d54811115613667576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f547279696e6720746f206c6f636b20666f7220746f6f206c6f6e6700000000006044820152606401610df0565b6040518060a001604052808781526020014281526020018560400151815260200186815260200161369783610e40565b90523360009081526022602052604090208054859081106136ba576136ba6154da565b9060005260206000209060050201600082015181600001556020820151816001015560408201518160020155606082015181600301556080820151816004015590505061370a3360006001614bfa565b6040805187815260208101839052428183015260608101879052905133917fc2cf1aae6decacbc52f96b4e4fec96d4ebab5236e4ed987165537bc463014a43919081900360800190a25050600160025550505050565b73ffffffffffffffffffffffffffffffffffffffff81166000908152601f6020526040812054610e6690670de0b6b3a764000090610d18906116b1611997565b60005473ffffffffffffffffffffffffffffffffffffffff163314806137dd575060085473ffffffffffffffffffffffffffffffffffffffff1633145b613843576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b00000000000000000000006044820152606401610df0565b602580547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff81166101009182900460ff1615909102179055565b60255460ff1615156001146138ee576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f4e6f7420696e206d6967726174696f6e000000000000000000000000000000006044820152606401610df0565b73ffffffffffffffffffffffffffffffffffffffff8216600090815260246020908152604080832033845290915290205460ff16801561393d57503360009081526023602052604090205460ff165b6139a3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f4d69672e20696e76616c6964206f7220756e617070726f7665640000000000006044820152606401610df0565b6139b082338360016145e4565b5050565b73ffffffffffffffffffffffffffffffffffffffff811660009081526023602052604090205460ff16613a43576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f496e76616c6964206d69677261746f72206164647265737300000000000000006044820152606401610df0565b33600090815260246020908152604080832073ffffffffffffffffffffffffffffffffffffffff9490941683529290522080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b6012818154811061232457600080fd5b6025546601000000000000900460ff16613b25576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f436f6e7472616374206e6f7420696e697469616c697a656400000000000000006044820152606401610df0565b60255465010000000000900460ff1615613b9b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f4f6e6c79207769746864726177616c7320616c6c6f77656400000000000000006044820152606401610df0565b613ba3614d8d565b42600b819055601554613bb69190613cfe565b600a55565b6000613bfd83836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f77000081525061509b565b9392505050565b600082600003613c1657506000610e66565b6000613c228385615538565b905082613c2f858361554f565b14613bfd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602160248201527f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f60448201527f77000000000000000000000000000000000000000000000000000000000000006064820152608401610df0565b6000613bfd83836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f0000000000008152506150e6565b600080613d0b8385615671565b905083811015613bfd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f7700000000006044820152606401610df0565b6000818310613d865781613bfd565b5090919050565b846001613d9c82826000614bfa565b602554640100000000900460ff161580613dca57503360009081526023602052604090205460ff1615156001145b613e30576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f5374616b696e6720706175736564206f7220696e206d6967726174696f6e00006044820152606401610df0565b60255465010000000000900460ff1615613ea6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f4f6e6c79207769746864726177616c7320616c6c6f77656400000000000000006044820152606401610df0565b60008511613f10576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f4d757374207374616b65206d6f7265207468616e207a65726f000000000000006044820152606401610df0565b600e54841015613f7c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f4d696e696d756d207374616b652074696d65206e6f74206d65740000000000006044820152606401610df0565b600d54841115613fe8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f547279696e6720746f206c6f636b20666f7220746f6f206c6f6e6700000000006044820152606401610df0565b6000613ff385610e40565b73ffffffffffffffffffffffffffffffffffffffff89166000908152601f602090815260408083205490517fffffffffffffffffffffffffffffffffffffffff00000000000000000000000060608e901b169281019290925260348201889052605482018a9052607482015291925090609401604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152828252805160209182012073ffffffffffffffffffffffffffffffffffffffff8d1660009081526022835283902060a0850184528185529184018990529183018a905290925090606081016140e6888a613cfe565b8152602090810185905282546001818101855560009485529382902083516005928302909101908155918301519382019390935560408201516002820155606082015160038201556080909101516004909101555461415d9073ffffffffffffffffffffffffffffffffffffffff1689308a614a5c565b601d5461416a9088613cfe565b601d5573ffffffffffffffffffffffffffffffffffffffff89166000908152601f602052604090205461419d9088613cfe565b73ffffffffffffffffffffffffffffffffffffffff8a166000908152601f60205260408120919091556141d3908a906001614bfa565b604080518881526020810188905290810182905273ffffffffffffffffffffffffffffffffffffffff89811660608301528a16907ff400e72e69ef4402819dfc57eeddc66f5eb69bf405e0e8098b1946ec1ac14a229060800160405180910390a2505050505050505050565b606082600161425082826000614bfa565b60255465010000000000900460ff16156142c6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f4f6e6c79207769746864726177616c7320616c6c6f77656400000000000000006044820152606401610df0565b60045467ffffffffffffffff8111156142e1576142e16154ab565b60405190808252806020026020018201604052801561430a578160200160208202803683370190505b50925060005b6004548110156145b45773ffffffffffffffffffffffffffffffffffffffff86166000908152601a60209081526040808320848452909152902054845185908390811061435f5761435f6154da565b602002602001018181525050600084828151811061437f5761437f6154da565b602002602001015111156145ac5773ffffffffffffffffffffffffffffffffffffffff86166000908152601a6020908152604080832084845290915281205560048054829081106143d2576143d26154da565b9060005260206000200160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a9059cbb8686848151811061442b5761442b6154da565b60200260200101516040518363ffffffff1660e01b815260040161447192919073ffffffffffffffffffffffffffffffffffffffff929092168252602082015260400190565b6020604051808303816000875af1158015614490573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906144b49190615684565b508381815181106144c7576144c76154da565b6020026020010151601782815481106144e2576144e26154da565b9060005260206000200160008282546144fb9190615671565b925050819055508573ffffffffffffffffffffffffffffffffffffffff167f1d2f2ca53af5d2f333bd32fdd45f9c52ad8ebe31414f7792912077fcb3876dff85838151811061454c5761454c6154da565b602002602001015160048481548110614567576145676154da565b600091825260209182902001546040805193845273ffffffffffffffffffffffffffffffffffffffff9182169284019290925289169082015260600160405180910390a25b600101614310565b50505073ffffffffffffffffffffffffffffffffffffffff9092166000908152601c602052604090204290555090565b60255465010000000000900460ff1661460357614601848461423f565b505b600080614610868561488e565b91509150816060015142101580614634575060255460ff6101009091041615156001145b8061465357503360009081526023602052604090205460ff1615156001145b6146b9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f5374616b65206973207374696c6c206c6f636b656421000000000000000000006044820152606401610df0565b6040820151801561488557601d546146d19082613bbb565b601d5573ffffffffffffffffffffffffffffffffffffffff87166000908152601f60205260409020546147049082613bbb565b73ffffffffffffffffffffffffffffffffffffffff88166000908152601f60209081526040808320939093556022905220805483908110614747576147476154da565b90600052602060002090600502016000808201600090556001820160009055600282016000905560038201600090556004820160009055505061478c87600180614bfa565b6005546040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8881166004830152602482018490529091169063a9059cbb906044016020604051808303816000875af1158015614805573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906148299190615684565b50604080518281526020810187905273ffffffffffffffffffffffffffffffffffffffff888116828401529151918916917f1d9308f6b22a2754a1c622bb30889e8f8f956c83e524d039e9d65d5f052eb9089181900360600190a25b50505050505050565b6148c36040518060a0016040528060008019168152602001600081526020016000815260200160008152602001600081525090565b600082156149e05760005b73ffffffffffffffffffffffffffffffffffffffff85166000908152602260205260409020548110156149de5773ffffffffffffffffffffffffffffffffffffffff85166000908152602260205260409020805482908110614932576149326154da565b90600052602060002090600502016000015484036149d65773ffffffffffffffffffffffffffffffffffffffff85166000908152602260205260409020805482908110614981576149816154da565b90600052602060002090600502016040518060a00160405290816000820154815260200160018201548152602001600282015481526020016003820154815260200160048201548152505092508091506149de565b6001016148ce565b505b82158015906149ef5750815183145b614a55576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f5374616b65206e6f7420666f756e6400000000000000000000000000000000006044820152606401610df0565b9250929050565b6040805173ffffffffffffffffffffffffffffffffffffffff85811660248301528481166044830152606480830185905283518084039091018152608490920183526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f23b872dd000000000000000000000000000000000000000000000000000000001790529151600092839290881691614afb91906156a1565b6000604051808303816000865af19150503d8060008114614b38576040519150601f19603f3d011682016040523d82523d6000602084013e614b3d565b606091505b5091509150818015614b67575080511580614b67575080806020019051810190614b679190615684565b614bf2576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f5472616e7366657248656c7065723a205452414e534645525f46524f4d5f464160448201527f494c4544000000000000000000000000000000000000000000000000000000006064820152608401610df0565b505050505050565b60255465010000000000900460ff16614c1b578115614c1b57614c1b613aaf565b8015614c5157614c2a836115d3565b73ffffffffffffffffffffffffffffffffffffffff84166000908152601160205260409020555b73ffffffffffffffffffffffffffffffffffffffff831615614d75576000806000614c7b86612559565b602554929550909350915065010000000000900460ff16614c9f57614c9f8661512e565b73ffffffffffffffffffffffffffffffffffffffff86166000908152601160205260409020829055828110614d22576000614cda8285613bbb565b601e54909150614cea9082613cfe565b601e55614cf78482613cfe565b73ffffffffffffffffffffffffffffffffffffffff8816600090815260208052604090205550614bf2565b6000614d2e8483613bbb565b601e54909150614d3e9082613bbb565b601e55614d4b8482613bbb565b73ffffffffffffffffffffffffffffffffffffffff88166000908152602080526040902055505050505b505050565b6000614d8842600a54613d77565b905090565b601554601b54614d9e904290613bbb565b10614e5b5760065473ffffffffffffffffffffffffffffffffffffffff1615614e5657600660009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16638f73c5ae6040518163ffffffff1660e01b81526004016020604051808303816000875af1158015614e30573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614e54919061558a565b505b42601b555b6000614e7d614e75600b5442613bbb90919063ffffffff16565b601554613d77565b90506000614e896130d7565b905060005b600454811015614d7557600060048281548110614ead57614ead6154da565b6000918252602090912001546040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff909116906370a0823190602401602060405180830381865afa158015614f24573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614f48919061558a565b9050614f6184601284815481106113a4576113a46154da565b60168381548110614f7457614f746154da565b906000526020600020016000828254614f8d9190615671565b92505081905550828281518110614fa657614fa66154da565b602002602001015160188381548110614fc157614fc16154da565b9060005260206000200181905550600061501e60178481548110614fe757614fe76154da565b906000526020600020015460168581548110615005576150056154da565b9060005260206000200154613bbb90919063ffffffff16565b905080821161504d5760006012848154811061503c5761503c6154da565b600091825260209091200155615091565b60006150598383613bbb565b905061507060155482613cbc90919063ffffffff16565b60128581548110615083576150836154da565b600091825260209091200155505b5050600101614e8e565b600081848411156150d9576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610df09190615393565b506000611b1a848661565e565b60008183615121576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610df09190615393565b506000611b1a848661554f565b73ffffffffffffffffffffffffffffffffffffffff81161561520757600061515582610b9b565b905060005b600454811015614d7557818181518110615176576151766154da565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff85166000908152601a83526040808220858352909352919091205560188054829081106151c6576151c66154da565b600091825260208083209091015473ffffffffffffffffffffffffffffffffffffffff8616835260198252604080842085855290925291205560010161515a565b50565b803573ffffffffffffffffffffffffffffffffffffffff81168114610d4c57600080fd5b60006020828403121561524057600080fd5b613bfd8261520a565b6020808252825182820181905260009190848201906040850190845b8181101561528157835183529284019291840191600101615265565b50909695505050505050565b60006020828403121561529f57600080fd5b5035919050565b600080604083850312156152b957600080fd5b50508035926020909101359150565b602080825282518282018190526000919060409081850190868401855b828110156153295781518051855286810151878601528581015186860152606080820151908601526080908101519085015260a090930192908501906001016152e5565b5091979650505050505050565b6000806000806080858703121561534c57600080fd5b6153558561520a565b966020860135965060408601359560600135945092505050565b60005b8381101561538a578181015183820152602001615372565b50506000910152565b60208152600082518060208401526153b281604085016020870161536f565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169190910160400192915050565b6000806000606084860312156153f957600080fd5b505081359360208301359350604090920135919050565b6000806040838503121561542357600080fd5b61542c8361520a565b946020939093013593505050565b801515811461520757600080fd5b6000806040838503121561545b57600080fd5b82359150602083013561546d8161543a565b809150509250929050565b6000806040838503121561548b57600080fd5b6154948361520a565b91506154a26020840161520a565b90509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b8082028115828204841417610e6657610e66615509565b600082615585577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b60006020828403121561559c57600080fd5b5051919050565b600181811c908216806155b757607f821691505b602082108103610c44577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b80516dffffffffffffffffffffffffffff81168114610d4c57600080fd5b60008060006060848603121561562357600080fd5b61562c846155f0565b925061563a602085016155f0565b9150604084015163ffffffff8116811461565357600080fd5b809150509250925092565b81810381811115610e6657610e66615509565b80820180821115610e6657610e66615509565b60006020828403121561569657600080fd5b8151613bfd8161543a565b600082516156b381846020870161536f565b919091019291505056fea26469706673582212203f019bfa0dfa21e47e837705158f7cb00b04eca5bc59099971f9825dec0548dc64736f6c63430008170033000000000000000000000000c4eb45d80dc1f079045e75d5d55de8ed1c1090e600000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000b4da8da10fff1f6127ab71395053aa1d499b503f000000000000000000000000fc00000000000000000000000000000000000001000000000000000000000000c4eb45d80dc1f079045e75d5d55de8ed1c1090e600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000fc00000000000000000000000000000000000002
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106105135760003560e01c80637bb7bed1116102a1578063cd3daf9d1161016b578063e9f2838e116100e3578063f288baf611610097578063f2caeb1e1161007c578063f2caeb1e14610b73578063fce6fd1314610b86578063fff6cae914610b9357600080fd5b8063f288baf614610b61578063f2a8d34914610b6a57600080fd5b8063ebe2b12b116100c8578063ebe2b12b14610b22578063ee89e02f14610b2b578063f12f144714610b4e57600080fd5b8063e9f2838e14610afc578063eb3c209e14610b0f57600080fd5b8063d42fc9b41161013a578063dcc3e06e1161011f578063dcc3e06e14610acc578063e01f62bf14610aec578063e1ba95d214610af457600080fd5b8063d42fc9b414610a83578063d9f96e8d14610a9657600080fd5b8063cd3daf9d14610a57578063cdc82e8014610a5f578063d239f00314610a68578063d2fbdc0d14610a7057600080fd5b80639b8c15a811610219578063b85efd06116101cd578063bbb781cc116101b2578063bbb781cc14610a26578063bdacb30314610a3b578063c8f33c9114610a4e57600080fd5b8063b85efd0614610a0a578063b94c4dcb14610a1d57600080fd5b8063a2217bc5116101fe578063a2217bc5146109dc578063a65fd70a146109e4578063af00f4e2146109f757600080fd5b80639b8c15a81461099b5780639c5303eb146109c957600080fd5b80638bad86a711610270578063903bd2af11610255578063903bd2af1461096357806392eefe9b146109765780639637927f1461098957600080fd5b80638bad86a7146109155780638da5cb5b1461094357600080fd5b80637bb7bed1146108c6578063818a2ba6146108d95780638980f11f146108ec57806389b5f00b146108ff57600080fd5b806341edbdf0116103e25780636885d3161161035a57806372f702f31161030e5780637970833e116102f35780637970833e1461087b57806379ba5097146108b65780637b31c19a146108be57600080fd5b806372f702f314610848578063774d4ae71461086857600080fd5b80636ce46bc31161033f5780636ce46bc3146108235780636cea0b0d146108365780636e27cef91461083f57600080fd5b80636885d316146107fb578063693392451461080357600080fd5b806352732bc8116103b157806354fd4d501161039657806354fd4d50146107e35780635bfd9258146107eb57806364f2c060146107f357600080fd5b806352732bc81461075c57806353a47bb7146107c357600080fd5b806341edbdf0146106f45780634b24ea47146107095780634bc66f32146107295780634fd2b5361461074957600080fd5b80631c1f78eb1161049057806336f89af211610444578063392e53cd11610429578063392e53cd146106cd5780633b8105b3146106e45780633d18b912146106ec57600080fd5b806336f89af21461068f578063386a9525146106c457600080fd5b806328ef934e1161047557806328ef934e146106455780632c0c2a0a14610658578063323331ca1461066b57600080fd5b80631c1f78eb1461061d5780631e090f011461062557600080fd5b8063169d27ef116104e757806317b18c89116104cc57806317b18c89146105d757806319ff52fd146105ea5780631b3e870a1461060a57600080fd5b8063169d27ef1461058a578063174ed0ca1461059257600080fd5b80628cc26214610518578063046e7d3f146105415780630d7bac4f146105565780631627540c14610577575b600080fd5b61052b61052636600461522e565b610b9b565b6040516105389190615249565b60405180910390f35b61055461054f36600461522e565b610d51565b005b61056961056436600461528d565b610e40565b604051908152602001610538565b61055461058536600461522e565b610e6c565b610554610f8c565b6007546105b29073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610538565b6105546105e53660046152a6565b61112c565b6003546105b29073ffffffffffffffffffffffffffffffffffffffff1681565b61055461061836600461522e565b6111b1565b61052b611334565b61063861063336600461522e565b6113e6565b60405161053891906152c8565b610554610653366004615336565b61149a565b61056961066636600461522e565b6115d3565b60255461067f906301000000900460ff1681565b6040519015158152602001610538565b61056961069d36600461522e565b73ffffffffffffffffffffffffffffffffffffffff16600090815260208052604090205490565b61056960155481565b60255461067f906601000000000000900460ff1681565b610554611706565b61052b6117e6565b6106fc6118df565b6040516105389190615393565b6009546105b29073ffffffffffffffffffffffffffffffffffffffff1681565b6008546105b29073ffffffffffffffffffffffffffffffffffffffff1681565b61056961075736600461522e565b61196d565b61055461076a36600461522e565b33600090815260246020908152604080832073ffffffffffffffffffffffffffffffffffffffff9490941683529290522080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055565b6001546105b29073ffffffffffffffffffffffffffffffffffffffff1681565b6106fc61198a565b610569611997565b601e54610569565b610554611b23565b61056961081136600461522e565b60146020526000908152604090205481565b6105546108313660046153e4565b611bf8565b610569601b5481565b610569600e5481565b6005546105b29073ffffffffffffffffffffffffffffffffffffffff1681565b610569610876366004615410565b611e59565b61088e610889366004615410565b612065565b604080519586526020860194909452928401919091526060830152608082015260a001610538565b6105546120b3565b6105546121fe565b6105b26108d436600461528d565b6122dd565b6105696108e736600461528d565b612314565b6105546108fa366004615410565b612335565b60255461067f9065010000000000900460ff1681565b61092861092336600461522e565b612559565b60408051938452602084019290925290820152606001610538565b6000546105b29073ffffffffffffffffffffffffffffffffffffffff1681565b610554610971366004615448565b612784565b61055461098436600461522e565b612872565b60255461067f90610100900460ff1681565b61067f6109a9366004615478565b602460209081526000928352604080842090915290825290205460ff1681565b6105546109d736600461522e565b61295c565b610554612a4e565b6105696109f236600461528d565b612b23565b610554610a053660046152a6565b612b33565b610554610a183660046152a6565b612d19565b610569600d5481565b60255461067f90640100000000900460ff1681565b610554610a4936600461522e565b612fed565b610569600b5481565b61052b6130d7565b610569600c5481565b610554613235565b610554610a7e3660046152a6565b613313565b610569610a9136600461522e565b613760565b610569610aa436600461522e565b73ffffffffffffffffffffffffffffffffffffffff166000908152601f602052604090205490565b6006546105b29073ffffffffffffffffffffffffffffffffffffffff1681565b601d54610569565b6105546137a0565b60255461067f9062010000900460ff1681565b610554610b1d366004615410565b61387d565b610569600a5481565b61067f610b3936600461522e565b60236020526000908152604090205460ff1681565b610554610b5c36600461522e565b6139b4565b61056960105481565b610569600f5481565b610569610b8136600461528d565b613a9f565b60255461067f9060ff1681565b610554613aaf565b60045460609067ffffffffffffffff811115610bb957610bb96154ab565b604051908082528060200260200182016040528015610be2578160200160208202803683370190505b5073ffffffffffffffffffffffffffffffffffffffff8316600090815260208052604081205491925003610c4a5760005b600454811015610c44576000828281518110610c3157610c316154da565b6020908102919091010152600101610c13565b50919050565b6000610c546130d7565b905060005b600454811015610d495773ffffffffffffffffffffffffffffffffffffffff84166000818152601a60209081526040808320858452825280832054938352601982528083208584529091529020548351610d249291610d1e91670de0b6b3a764000091610d1891610ced9190899089908110610cd757610cd76154da565b6020026020010151613bbb90919063ffffffff16565b73ffffffffffffffffffffffffffffffffffffffff8a16600090815260208052604090205490613c04565b90613cbc565b90613cfe565b838281518110610d3657610d366154da565b6020908102919091010152600101610c59565b50505b919050565b60005473ffffffffffffffffffffffffffffffffffffffff16331480610d8e575060085473ffffffffffffffffffffffffffffffffffffffff1633145b610df9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b000000000000000000000060448201526064015b60405180910390fd5b600380547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b600c54600d54600091610e6691610e578286615538565b610e61919061554f565b613d77565b92915050565b60005473ffffffffffffffffffffffffffffffffffffffff163314610f13576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602f60248201527f4f6e6c792074686520636f6e7472616374206f776e6572206d6179207065726660448201527f6f726d207468697320616374696f6e00000000000000000000000000000000006064820152608401610df0565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040519081527f906a1c6bd7e3091ea86693dd029a831c19049ce77f1dce2ce0bab1cacbabce229060200160405180910390a150565b60005473ffffffffffffffffffffffffffffffffffffffff16331480610fc9575060085473ffffffffffffffffffffffffffffffffffffffff1633145b80610feb575060095473ffffffffffffffffffffffffffffffffffffffff1633145b611051576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4e6f74206f776e2c20746c6b2c206f72206374726c72000000000000000000006044820152606401610df0565b6025546601000000000000900460ff16156110c8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f416c726561647920696e697469616c697a6564000000000000000000000000006044820152606401610df0565b602580547fffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffff166601000000000000179055611101613aaf565b6040517fb5cfe3ccd03847076864f081609024cbc2eb98c38da4d8b2cebe9479a9a1ef3790600090a1565b6002805403611197576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610df0565b600280556111a83380848442613d8d565b50506001600255565b60005473ffffffffffffffffffffffffffffffffffffffff163314806111ee575060085473ffffffffffffffffffffffffffffffffffffffff1633145b611254576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b00000000000000000000006044820152606401610df0565b73ffffffffffffffffffffffffffffffffffffffff811660009081526023602052604090205460ff1615156001146112e8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f41646472657373206e6f6e6578697374656e74000000000000000000000000006044820152606401610df0565b73ffffffffffffffffffffffffffffffffffffffff16600090815260236020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055565b60045460609067ffffffffffffffff811115611352576113526154ab565b60405190808252806020026020018201604052801561137b578160200160208202803683370190505b50905060005b6004548110156113e2576113bd601554601283815481106113a4576113a46154da565b9060005260206000200154613c0490919063ffffffff16565b8282815181106113cf576113cf6154da565b6020908102919091010152600101611381565b5090565b73ffffffffffffffffffffffffffffffffffffffff81166000908152602260209081526040808320805482518185028101850190935280835260609492939192909184015b8282101561148f57838290600052602060002090600502016040518060a0016040529081600082015481526020016001820154815260200160028201548152602001600382015481526020016004820154815250508152602001906001019061142b565b505050509050919050565b60255460ff16151560011461150b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f4e6f7420696e206d6967726174696f6e000000000000000000000000000000006044820152606401610df0565b73ffffffffffffffffffffffffffffffffffffffff8416600090815260246020908152604080832033845290915290205460ff16801561155a57503360009081526023602052604090205460ff165b6115c0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f4d69672e20696e76616c6964206f7220756e617070726f7665640000000000006044820152606401610df0565b6115cd8433858585613d8d565b50505050565b60035460009073ffffffffffffffffffffffffffffffffffffffff16156116fe5760006115ff8361196d565b905080156116f5576003546040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85811660048301526000926116b7928592610d1892670de0b6b3a7640000929116906370a0823190602401602060405180830381865afa15801561168d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116b1919061558a565b90613c04565b905060006116dc670de0b6b3a7640000610d1860105485613c0490919063ffffffff16565b90506010548111156116ed57506010545b949350505050565b50600092915050565b506000919050565b60005473ffffffffffffffffffffffffffffffffffffffff16331480611743575060085473ffffffffffffffffffffffffffffffffffffffff1633145b6117a9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b00000000000000000000006044820152606401610df0565b602580547fffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffff81166401000000009182900460ff1615909102179055565b60606002805403611853576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610df0565b600280556025546301000000900460ff16156118cb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f5265776172647320636f6c6c656374696f6e20706175736564000000000000006044820152606401610df0565b6118d5333361423f565b9050600160025590565b602780546118ec906155a3565b80601f0160208091040260200160405190810160405280929190818152602001828054611918906155a3565b80156119655780601f1061193a57610100808354040283529160200191611965565b820191906000526020600020905b81548152906001019060200180831161194857829003601f168201915b505050505081565b6000610e66670de0b6b3a7640000610d18600f546116b186613760565b602680546118ec906155a3565b6000806000806000600560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16630902f1ac6040518163ffffffff1660e01b8152600401606060405180830381865afa158015611a0c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a30919061560e565b506021546dffffffffffffffffffffffffffff92831694509116915060ff1615611a5c57819250611a60565b8092505b600560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611acd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611af1919061558a565b611b0384670de0b6b3a7640000615538565b611b0d919061554f565b9350611b1a600285615538565b95945050505050565b60005473ffffffffffffffffffffffffffffffffffffffff16331480611b60575060085473ffffffffffffffffffffffffffffffffffffffff1633145b611bc6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b00000000000000000000006044820152606401610df0565b602580547fffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffffff1665010000000000179055565b60005473ffffffffffffffffffffffffffffffffffffffff16331480611c35575060085473ffffffffffffffffffffffffffffffffffffffff1633145b611c9b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b00000000000000000000006044820152606401610df0565b670de0b6b3a7640000831015611d32576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f4d756c74206d757374206265203e3d204d554c5449504c4945525f505245434960448201527f53494f4e000000000000000000000000000000000000000000000000000000006064820152608401610df0565b60008111611d9c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f766546585320706374206d6178206d757374206265203e3d20300000000000006044820152606401610df0565b600c8390556010829055600f8190556040518281527fc9d56ccdd6b954d8d74700db074cc667054f8e33c1b8d23e97021d4c588a87619060200160405180910390a17fa1676084a9eea08c6f205b60799323b364a1bd8e10aba89f0fbd94cfbf68b5dd600c54604051611e1191815260200190565b60405180910390a17f58c7ececaeb4704a0039e0d22c1b618367f7a7b9a4e191ab9baed34898f63f2e600f54604051611e4c91815260200190565b60405180910390a1505050565b73ffffffffffffffffffffffffffffffffffffffff82166000908152602260205260408120805482919084908110611e9357611e936154da565b600091825260208083206040805160a081018252600590940290910180548452600181015484840181905260028201548584015260038201546060860152600490910154608085015273ffffffffffffffffffffffffffffffffffffffff89168552601c9092528320549193501115611f1157506020810151611f39565b5073ffffffffffffffffffffffffffffffffffffffff84166000908152601c60205260409020545b42826060015111611ff957606082015173ffffffffffffffffffffffffffffffffffffffff86166000908152601c60205260409020541015611ff0576000818360600151611f87919061565e565b90506000836060015142611f9b919061565e565b90506000611fad61056460028561554f565b90506000611fbb8382615538565b611fc58584615538565b611fcf9190615671565b9050611fdb8385615671565b611fe5908261554f565b965050505050612049565b60009250612049565b60008082846060015161200c919061565e565b90506000428560600151612020919061565e565b9050600261202e8284615671565b612038919061554f565b9250505061204581610e40565b9350505b816080015183111561205d57816080015192505b505092915050565b6022602052816000526040600020818154811061208157600080fd5b600091825260209091206005909102018054600182015460028301546003840154600490940154929550909350919085565b60015473ffffffffffffffffffffffffffffffffffffffff16331461215a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603560248201527f596f75206d757374206265206e6f6d696e61746564206265666f726520796f7560448201527f2063616e20616363657074206f776e65727368697000000000000000000000006064820152608401610df0565b6000546001546040805173ffffffffffffffffffffffffffffffffffffffff93841681529290911660208301527fb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159c910160405180910390a160018054600080547fffffffffffffffffffffffff000000000000000000000000000000000000000090811673ffffffffffffffffffffffffffffffffffffffff841617909155169055565b60005473ffffffffffffffffffffffffffffffffffffffff1633148061223b575060085473ffffffffffffffffffffffffffffffffffffffff1633145b6122a1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b00000000000000000000006044820152606401610df0565b602580547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffff811663010000009182900460ff1615909102179055565b600481815481106122ed57600080fd5b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff16905081565b6017818154811061232457600080fd5b600091825260209091200154905081565b60005473ffffffffffffffffffffffffffffffffffffffff16331480612372575060085473ffffffffffffffffffffffffffffffffffffffff1633145b6123d8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b00000000000000000000006044820152606401610df0565b60255460ff166124675760055473ffffffffffffffffffffffffffffffffffffffff90811690831603612467576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f4e6f7420696e206d6967726174696f6e000000000000000000000000000000006044820152606401610df0565b6000546040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9182166004820152602481018390529083169063a9059cbb906044016020604051808303816000875af11580156124e0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125049190615684565b506040805173ffffffffffffffffffffffffffffffffffffffff84168152602081018390527f8c1256b8896378cd5044f80c202f9772b9d77dc85c8a6eb51967210b09bfaa2891015b60405180910390a15050565b73ffffffffffffffffffffffffffffffffffffffff811660009081526020805260408120549080612589846115d3565b73ffffffffffffffffffffffffffffffffffffffff85166000908152601f6020526040812054919350901580156125e2575073ffffffffffffffffffffffffffffffffffffffff85166000908152602080526040902054155b80612612575073ffffffffffffffffffffffffffffffffffffffff85166000908152601160205260409020548310155b1561261e57508161265e565b73ffffffffffffffffffffffffffffffffffffffff85166000908152601160205260409020546002906126519085615671565b61265b919061554f565b90505b6000915060005b73ffffffffffffffffffffffffffffffffffffffff861660009081526022602052604090205481101561277b5773ffffffffffffffffffffffffffffffffffffffff861660009081526022602052604081208054839081106126c9576126c96154da565b90600052602060002090600502016040518060a001604052908160008201548152602001600182015481526020016002820154815260200160038201548152602001600482015481525050905060006127228884611e59565b60408301519091506000670de0b6b3a764000061273f8785615671565b6127499084615538565b612753919061554f565b61275d9083615671565b90506127698188615671565b96505060019093019250612665915050565b50509193909250565b60028054036127ef576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610df0565b6002805560255462010000900460ff1615612866576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f5769746864726177616c732070617573656400000000000000000000000000006044820152606401610df0565b6111a8333384846145e4565b60005473ffffffffffffffffffffffffffffffffffffffff163314806128af575060085473ffffffffffffffffffffffffffffffffffffffff1633145b612915576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b00000000000000000000006044820152606401610df0565b600980547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b60005473ffffffffffffffffffffffffffffffffffffffff16331480612999575060085473ffffffffffffffffffffffffffffffffffffffff1633145b6129ff576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b00000000000000000000006044820152606401610df0565b73ffffffffffffffffffffffffffffffffffffffff16600090815260236020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b60005473ffffffffffffffffffffffffffffffffffffffff16331480612a8b575060085473ffffffffffffffffffffffffffffffffffffffff1633145b612af1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b00000000000000000000006044820152606401610df0565b602580547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00811660ff90911615179055565b6016818154811061232457600080fd5b60005473ffffffffffffffffffffffffffffffffffffffff16331480612b70575060085473ffffffffffffffffffffffffffffffffffffffff1633145b612bd6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b00000000000000000000006044820152606401610df0565b6001821015612c41576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f4d756c206d61782074696d65206d757374206265203e3d2031000000000000006044820152606401610df0565b6001811015612cac576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f4d756c206d696e2074696d65206d757374206265203e3d2031000000000000006044820152606401610df0565b600d829055600e8190556040518281527f0e3e3fae480c6f92291358a02bc83f04ee1971d5488596bffda7929d57ab470f9060200160405180910390a16040518181527f0534d208d75dfdbfacc1204745dd9b3c4c37e8cfc05eb5e8e3ae538aedb0a9fa9060200161254d565b6002805403612d84576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610df0565b60028055602554640100000000900460ff1615612dfd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f5374616b696e67207061757365640000000000000000000000000000000000006044820152606401610df0565b60255465010000000000900460ff1615612e73576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f4f6e6c79207769746864726177616c7320616c6c6f77656400000000000000006044820152606401610df0565b612e7d333361423f565b50600080612e8b338561488e565b915091506000838360400151612ea19190615671565b9050600554612ec89073ffffffffffffffffffffffffffffffffffffffff16333087614a5c565b6040805160a081018252868152602085810151818301528183018490526060808701519083015260808087015190830152336000908152602290915291909120805484908110612f1a57612f1a6154da565b9060005260206000209060050201600082015181600001556020820151816001015560408201518160020155606082015181600301556080820151816004015590505083601d6000828254612f6f9190615671565b9091555050336000908152601f602052604081208054869290612f93908490615671565b90915550612fa690503360006001614bfa565b604080518681526020810186905233917f2640b32e7e5d0fa2a21ea06b22fbd75fda0fda384a895a5fdeef43646de47a0c910160405180910390a250506001600255505050565b60005473ffffffffffffffffffffffffffffffffffffffff1633148061302a575060085473ffffffffffffffffffffffffffffffffffffffff1633145b613090576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b00000000000000000000006044820152606401610df0565b600880547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b60045460609067ffffffffffffffff8111156130f5576130f56154ab565b60405190808252806020026020018201604052801561311e578160200160208202803683370190505b509050601d54600014806131325750601e54155b1561318d57601880548060200260200160405190810160405280929190818152602001828054801561318357602002820191906000526020600020905b81548152602001906001019080831161316f575b5050505050905090565b60005b6004548110156113e2576132106131e4601e54610d18670de0b6b3a76400006116b1601287815481106131c5576131c56154da565b90600052602060002001546116b1600b546131de614d7a565b90613bbb565b601883815481106131f7576131f76154da565b9060005260206000200154613cfe90919063ffffffff16565b828281518110613222576132226154da565b6020908102919091010152600101613190565b60005473ffffffffffffffffffffffffffffffffffffffff16331480613272575060085473ffffffffffffffffffffffffffffffffffffffff1633145b6132d8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b00000000000000000000006044820152606401610df0565b602580547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffff8116620100009182900460ff1615909102179055565b600280540361337e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610df0565b60028055602554640100000000900460ff16156133f7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f5374616b696e67207061757365640000000000000000000000000000000000006044820152606401610df0565b60255465010000000000900460ff161561346d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f4f6e6c79207769746864726177616c7320616c6c6f77656400000000000000006044820152606401610df0565b613477333361423f565b50600080613485338561488e565b915091504283116134f2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4d75737420626520696e207468652066757475726500000000000000000000006044820152606401610df0565b600042836060015111613506576000613516565b428360600151613516919061565e565b90506000613524428661565e565b905081811161358f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f43616e6e6f742073686f7274656e206c6f636b2074696d6500000000000000006044820152606401610df0565b600e548110156135fb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f4d696e696d756d207374616b652074696d65206e6f74206d65740000000000006044820152606401610df0565b600d54811115613667576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f547279696e6720746f206c6f636b20666f7220746f6f206c6f6e6700000000006044820152606401610df0565b6040518060a001604052808781526020014281526020018560400151815260200186815260200161369783610e40565b90523360009081526022602052604090208054859081106136ba576136ba6154da565b9060005260206000209060050201600082015181600001556020820151816001015560408201518160020155606082015181600301556080820151816004015590505061370a3360006001614bfa565b6040805187815260208101839052428183015260608101879052905133917fc2cf1aae6decacbc52f96b4e4fec96d4ebab5236e4ed987165537bc463014a43919081900360800190a25050600160025550505050565b73ffffffffffffffffffffffffffffffffffffffff81166000908152601f6020526040812054610e6690670de0b6b3a764000090610d18906116b1611997565b60005473ffffffffffffffffffffffffffffffffffffffff163314806137dd575060085473ffffffffffffffffffffffffffffffffffffffff1633145b613843576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b00000000000000000000006044820152606401610df0565b602580547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff81166101009182900460ff1615909102179055565b60255460ff1615156001146138ee576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f4e6f7420696e206d6967726174696f6e000000000000000000000000000000006044820152606401610df0565b73ffffffffffffffffffffffffffffffffffffffff8216600090815260246020908152604080832033845290915290205460ff16801561393d57503360009081526023602052604090205460ff165b6139a3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f4d69672e20696e76616c6964206f7220756e617070726f7665640000000000006044820152606401610df0565b6139b082338360016145e4565b5050565b73ffffffffffffffffffffffffffffffffffffffff811660009081526023602052604090205460ff16613a43576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f496e76616c6964206d69677261746f72206164647265737300000000000000006044820152606401610df0565b33600090815260246020908152604080832073ffffffffffffffffffffffffffffffffffffffff9490941683529290522080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b6012818154811061232457600080fd5b6025546601000000000000900460ff16613b25576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f436f6e7472616374206e6f7420696e697469616c697a656400000000000000006044820152606401610df0565b60255465010000000000900460ff1615613b9b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f4f6e6c79207769746864726177616c7320616c6c6f77656400000000000000006044820152606401610df0565b613ba3614d8d565b42600b819055601554613bb69190613cfe565b600a55565b6000613bfd83836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f77000081525061509b565b9392505050565b600082600003613c1657506000610e66565b6000613c228385615538565b905082613c2f858361554f565b14613bfd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602160248201527f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f60448201527f77000000000000000000000000000000000000000000000000000000000000006064820152608401610df0565b6000613bfd83836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f0000000000008152506150e6565b600080613d0b8385615671565b905083811015613bfd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f7700000000006044820152606401610df0565b6000818310613d865781613bfd565b5090919050565b846001613d9c82826000614bfa565b602554640100000000900460ff161580613dca57503360009081526023602052604090205460ff1615156001145b613e30576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f5374616b696e6720706175736564206f7220696e206d6967726174696f6e00006044820152606401610df0565b60255465010000000000900460ff1615613ea6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f4f6e6c79207769746864726177616c7320616c6c6f77656400000000000000006044820152606401610df0565b60008511613f10576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f4d757374207374616b65206d6f7265207468616e207a65726f000000000000006044820152606401610df0565b600e54841015613f7c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f4d696e696d756d207374616b652074696d65206e6f74206d65740000000000006044820152606401610df0565b600d54841115613fe8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f547279696e6720746f206c6f636b20666f7220746f6f206c6f6e6700000000006044820152606401610df0565b6000613ff385610e40565b73ffffffffffffffffffffffffffffffffffffffff89166000908152601f602090815260408083205490517fffffffffffffffffffffffffffffffffffffffff00000000000000000000000060608e901b169281019290925260348201889052605482018a9052607482015291925090609401604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152828252805160209182012073ffffffffffffffffffffffffffffffffffffffff8d1660009081526022835283902060a0850184528185529184018990529183018a905290925090606081016140e6888a613cfe565b8152602090810185905282546001818101855560009485529382902083516005928302909101908155918301519382019390935560408201516002820155606082015160038201556080909101516004909101555461415d9073ffffffffffffffffffffffffffffffffffffffff1689308a614a5c565b601d5461416a9088613cfe565b601d5573ffffffffffffffffffffffffffffffffffffffff89166000908152601f602052604090205461419d9088613cfe565b73ffffffffffffffffffffffffffffffffffffffff8a166000908152601f60205260408120919091556141d3908a906001614bfa565b604080518881526020810188905290810182905273ffffffffffffffffffffffffffffffffffffffff89811660608301528a16907ff400e72e69ef4402819dfc57eeddc66f5eb69bf405e0e8098b1946ec1ac14a229060800160405180910390a2505050505050505050565b606082600161425082826000614bfa565b60255465010000000000900460ff16156142c6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f4f6e6c79207769746864726177616c7320616c6c6f77656400000000000000006044820152606401610df0565b60045467ffffffffffffffff8111156142e1576142e16154ab565b60405190808252806020026020018201604052801561430a578160200160208202803683370190505b50925060005b6004548110156145b45773ffffffffffffffffffffffffffffffffffffffff86166000908152601a60209081526040808320848452909152902054845185908390811061435f5761435f6154da565b602002602001018181525050600084828151811061437f5761437f6154da565b602002602001015111156145ac5773ffffffffffffffffffffffffffffffffffffffff86166000908152601a6020908152604080832084845290915281205560048054829081106143d2576143d26154da565b9060005260206000200160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a9059cbb8686848151811061442b5761442b6154da565b60200260200101516040518363ffffffff1660e01b815260040161447192919073ffffffffffffffffffffffffffffffffffffffff929092168252602082015260400190565b6020604051808303816000875af1158015614490573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906144b49190615684565b508381815181106144c7576144c76154da565b6020026020010151601782815481106144e2576144e26154da565b9060005260206000200160008282546144fb9190615671565b925050819055508573ffffffffffffffffffffffffffffffffffffffff167f1d2f2ca53af5d2f333bd32fdd45f9c52ad8ebe31414f7792912077fcb3876dff85838151811061454c5761454c6154da565b602002602001015160048481548110614567576145676154da565b600091825260209182902001546040805193845273ffffffffffffffffffffffffffffffffffffffff9182169284019290925289169082015260600160405180910390a25b600101614310565b50505073ffffffffffffffffffffffffffffffffffffffff9092166000908152601c602052604090204290555090565b60255465010000000000900460ff1661460357614601848461423f565b505b600080614610868561488e565b91509150816060015142101580614634575060255460ff6101009091041615156001145b8061465357503360009081526023602052604090205460ff1615156001145b6146b9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f5374616b65206973207374696c6c206c6f636b656421000000000000000000006044820152606401610df0565b6040820151801561488557601d546146d19082613bbb565b601d5573ffffffffffffffffffffffffffffffffffffffff87166000908152601f60205260409020546147049082613bbb565b73ffffffffffffffffffffffffffffffffffffffff88166000908152601f60209081526040808320939093556022905220805483908110614747576147476154da565b90600052602060002090600502016000808201600090556001820160009055600282016000905560038201600090556004820160009055505061478c87600180614bfa565b6005546040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8881166004830152602482018490529091169063a9059cbb906044016020604051808303816000875af1158015614805573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906148299190615684565b50604080518281526020810187905273ffffffffffffffffffffffffffffffffffffffff888116828401529151918916917f1d9308f6b22a2754a1c622bb30889e8f8f956c83e524d039e9d65d5f052eb9089181900360600190a25b50505050505050565b6148c36040518060a0016040528060008019168152602001600081526020016000815260200160008152602001600081525090565b600082156149e05760005b73ffffffffffffffffffffffffffffffffffffffff85166000908152602260205260409020548110156149de5773ffffffffffffffffffffffffffffffffffffffff85166000908152602260205260409020805482908110614932576149326154da565b90600052602060002090600502016000015484036149d65773ffffffffffffffffffffffffffffffffffffffff85166000908152602260205260409020805482908110614981576149816154da565b90600052602060002090600502016040518060a00160405290816000820154815260200160018201548152602001600282015481526020016003820154815260200160048201548152505092508091506149de565b6001016148ce565b505b82158015906149ef5750815183145b614a55576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f5374616b65206e6f7420666f756e6400000000000000000000000000000000006044820152606401610df0565b9250929050565b6040805173ffffffffffffffffffffffffffffffffffffffff85811660248301528481166044830152606480830185905283518084039091018152608490920183526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f23b872dd000000000000000000000000000000000000000000000000000000001790529151600092839290881691614afb91906156a1565b6000604051808303816000865af19150503d8060008114614b38576040519150601f19603f3d011682016040523d82523d6000602084013e614b3d565b606091505b5091509150818015614b67575080511580614b67575080806020019051810190614b679190615684565b614bf2576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f5472616e7366657248656c7065723a205452414e534645525f46524f4d5f464160448201527f494c4544000000000000000000000000000000000000000000000000000000006064820152608401610df0565b505050505050565b60255465010000000000900460ff16614c1b578115614c1b57614c1b613aaf565b8015614c5157614c2a836115d3565b73ffffffffffffffffffffffffffffffffffffffff84166000908152601160205260409020555b73ffffffffffffffffffffffffffffffffffffffff831615614d75576000806000614c7b86612559565b602554929550909350915065010000000000900460ff16614c9f57614c9f8661512e565b73ffffffffffffffffffffffffffffffffffffffff86166000908152601160205260409020829055828110614d22576000614cda8285613bbb565b601e54909150614cea9082613cfe565b601e55614cf78482613cfe565b73ffffffffffffffffffffffffffffffffffffffff8816600090815260208052604090205550614bf2565b6000614d2e8483613bbb565b601e54909150614d3e9082613bbb565b601e55614d4b8482613bbb565b73ffffffffffffffffffffffffffffffffffffffff88166000908152602080526040902055505050505b505050565b6000614d8842600a54613d77565b905090565b601554601b54614d9e904290613bbb565b10614e5b5760065473ffffffffffffffffffffffffffffffffffffffff1615614e5657600660009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16638f73c5ae6040518163ffffffff1660e01b81526004016020604051808303816000875af1158015614e30573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614e54919061558a565b505b42601b555b6000614e7d614e75600b5442613bbb90919063ffffffff16565b601554613d77565b90506000614e896130d7565b905060005b600454811015614d7557600060048281548110614ead57614ead6154da565b6000918252602090912001546040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff909116906370a0823190602401602060405180830381865afa158015614f24573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614f48919061558a565b9050614f6184601284815481106113a4576113a46154da565b60168381548110614f7457614f746154da565b906000526020600020016000828254614f8d9190615671565b92505081905550828281518110614fa657614fa66154da565b602002602001015160188381548110614fc157614fc16154da565b9060005260206000200181905550600061501e60178481548110614fe757614fe76154da565b906000526020600020015460168581548110615005576150056154da565b9060005260206000200154613bbb90919063ffffffff16565b905080821161504d5760006012848154811061503c5761503c6154da565b600091825260209091200155615091565b60006150598383613bbb565b905061507060155482613cbc90919063ffffffff16565b60128581548110615083576150836154da565b600091825260209091200155505b5050600101614e8e565b600081848411156150d9576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610df09190615393565b506000611b1a848661565e565b60008183615121576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610df09190615393565b506000611b1a848661554f565b73ffffffffffffffffffffffffffffffffffffffff81161561520757600061515582610b9b565b905060005b600454811015614d7557818181518110615176576151766154da565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff85166000908152601a83526040808220858352909352919091205560188054829081106151c6576151c66154da565b600091825260208083209091015473ffffffffffffffffffffffffffffffffffffffff8616835260198252604080842085855290925291205560010161515a565b50565b803573ffffffffffffffffffffffffffffffffffffffff81168114610d4c57600080fd5b60006020828403121561524057600080fd5b613bfd8261520a565b6020808252825182820181905260009190848201906040850190845b8181101561528157835183529284019291840191600101615265565b50909695505050505050565b60006020828403121561529f57600080fd5b5035919050565b600080604083850312156152b957600080fd5b50508035926020909101359150565b602080825282518282018190526000919060409081850190868401855b828110156153295781518051855286810151878601528581015186860152606080820151908601526080908101519085015260a090930192908501906001016152e5565b5091979650505050505050565b6000806000806080858703121561534c57600080fd5b6153558561520a565b966020860135965060408601359560600135945092505050565b60005b8381101561538a578181015183820152602001615372565b50506000910152565b60208152600082518060208401526153b281604085016020870161536f565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169190910160400192915050565b6000806000606084860312156153f957600080fd5b505081359360208301359350604090920135919050565b6000806040838503121561542357600080fd5b61542c8361520a565b946020939093013593505050565b801515811461520757600080fd5b6000806040838503121561545b57600080fd5b82359150602083013561546d8161543a565b809150509250929050565b6000806040838503121561548b57600080fd5b6154948361520a565b91506154a26020840161520a565b90509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b8082028115828204841417610e6657610e66615509565b600082615585577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b60006020828403121561559c57600080fd5b5051919050565b600181811c908216806155b757607f821691505b602082108103610c44577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b80516dffffffffffffffffffffffffffff81168114610d4c57600080fd5b60008060006060848603121561562357600080fd5b61562c846155f0565b925061563a602085016155f0565b9150604084015163ffffffff8116811461565357600080fd5b809150509250925092565b81810381811115610e6657610e66615509565b80820180821115610e6657610e66615509565b60006020828403121561569657600080fd5b8151613bfd8161543a565b600082516156b381846020870161536f565b919091019291505056fea26469706673582212203f019bfa0dfa21e47e837705158f7cb00b04eca5bc59099971f9825dec0548dc64736f6c63430008170033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000c4eb45d80dc1f079045e75d5d55de8ed1c1090e600000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000b4da8da10fff1f6127ab71395053aa1d499b503f000000000000000000000000fc00000000000000000000000000000000000001000000000000000000000000c4eb45d80dc1f079045e75d5d55de8ed1c1090e600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000fc00000000000000000000000000000000000002
-----Decoded View---------------
Arg [0] : _owner (address): 0xC4EB45d80DC1F079045E75D5d55de8eD1c1090E6
Arg [1] : _rewardTokens (address[]): 0xFc00000000000000000000000000000000000002
Arg [2] : _stakingToken (address): 0xb4dA8dA10ffF1F6127ab71395053Aa1d499b503F
Arg [3] : _fraxAddress (address): 0xFc00000000000000000000000000000000000001
Arg [4] : _timelockAddress (address): 0xC4EB45d80DC1F079045E75D5d55de8eD1c1090E6
Arg [5] : _rewarder_address (address): 0x0000000000000000000000000000000000000000
-----Encoded View---------------
8 Constructor Arguments found :
Arg [0] : 000000000000000000000000c4eb45d80dc1f079045e75d5d55de8ed1c1090e6
Arg [1] : 00000000000000000000000000000000000000000000000000000000000000c0
Arg [2] : 000000000000000000000000b4da8da10fff1f6127ab71395053aa1d499b503f
Arg [3] : 000000000000000000000000fc00000000000000000000000000000000000001
Arg [4] : 000000000000000000000000c4eb45d80dc1f079045e75d5d55de8ed1c1090e6
Arg [5] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [6] : 0000000000000000000000000000000000000000000000000000000000000001
Arg [7] : 000000000000000000000000fc00000000000000000000000000000000000002
Deployed Bytecode Sourcemap
156391:472:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;126797:720;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;152732:113;;;;;;:::i;:::-;;:::i;:::-;;109765:222;;;;;;:::i;:::-;;:::i;:::-;;;1374:25:1;;;1362:2;1347:18;109765:222:0;1228:177:1;34855:141:0;;;;;;:::i;:::-;;:::i;146389:242::-;;;:::i;98554:26::-;;;;;;;;;;;;1586:42:1;1574:55;;;1556:74;;1544:2;1529:18;98554:26:0;1410:226:1;136341:163:0;;;;;;:::i;:::-;;:::i;95399:19::-;;;;;;;;;148162:261;;;;;;:::i;:::-;;:::i;127683:322::-;;;:::i;109457:133::-;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;146975:357::-;;;;;;:::i;:::-;;:::i;119451:1055::-;;;;;;:::i;:::-;;:::i;102990:35::-;;;;;;;;;;;;;;;3717:14:1;;3710:22;3692:41;;3680:2;3665:18;102990:35:0;3552:187:1;109212:127:0;;;;;;:::i;:::-;109305:26;;109278:7;109305:26;;;:17;:26;;;;;;;109212:127;100412:39;;;;;;103652:25;;;;;;;;;;;;151686:96;;;:::i;141754:210::-;;;:::i;156456:46::-;;;:::i;:::-;;;;;;;:::i;98833:32::-;;;;;;;;;98748:30;;;;;;;;;119116:187;;;;;;:::i;:::-;;:::i;135862:183::-;;;;;;:::i;:::-;136008:10;135983:36;;;;:24;:36;;;;;;;;;:54;;;;;;;;;;135976:61;;;;;;135862:183;34623:29;;;;;;;;;103711:31;;;:::i;110429:8163::-;;;:::i;108991:111::-;109072:22;;108991:111;;151521:112;;;:::i;100295:55::-;;;;;;:::i;:::-;;;;;;;;;;;;;;149608:796;;;;;;:::i;:::-;;:::i;101465:29::-;;;;;;99421:32;;;;;;98005:33;;;;;;;;;120768:2692;;;;;;:::i;:::-;;:::i;102278:53::-;;;;;;:::i;:::-;;:::i;:::-;;;;5551:25:1;;;5607:2;5592:18;;5585:34;;;;5635:18;;;5628:34;;;;5693:2;5678:18;;5671:34;5736:3;5721:19;;5714:35;5538:3;5523:19;102278:53:0;5292:463:1;35004:271:0;;;:::i;152009:126::-;;;:::i;95475:29::-;;;;;;:::i;:::-;;:::i;100843:28::-;;;;;;:::i;:::-;;:::i;148667:553::-;;;;;;:::i;:::-;;:::i;103549:34::-;;;;;;;;;;;;123785:1952;;;;;;:::i;:::-;;:::i;:::-;;;;5962:25:1;;;6018:2;6003:18;;5996:34;;;;6046:18;;;6039:34;5950:2;5935:18;123785:1952:0;5760:319:1;34596:20:0;;;;;;;;;139065:251;;;;;;:::i;:::-;;:::i;152498:130::-;;;;;;:::i;:::-;;:::i;102815:26::-;;;;;;;;;;;;102521:76;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;147921:128;;;;;;:::i;:::-;;:::i;151377:97::-;;;:::i;100731:28::-;;;;;;:::i;:::-;;:::i;150618:537::-;;;;;;:::i;:::-;;:::i;131439:1445::-;;;;;;:::i;:::-;;:::i;99292:61::-;;;;;;103095:25;;;;;;;;;;;;152254:116;;;;;;:::i;:::-;;:::i;99026:29::-;;;;;;125884:704;;;:::i;99145:50::-;;;;;;151838:108;;;:::i;133117:1642::-;;;;;;:::i;:::-;;:::i;118740:157::-;;;;;;:::i;:::-;;:::i;108641:128::-;;;;;;:::i;:::-;108735:26;;108708:7;108735:26;;;:17;:26;;;;;;;108641:128;98470:38;;;;;;;;;108383:113;108465:23;;108383:113;;151227:97;;;:::i;102897:29::-;;;;;;;;;;;;147496:304;;;;;;:::i;:::-;;:::i;98933:27::-;;;;;;102401:47;;;;;;:::i;:::-;;;;;;;;;;;;;;;;135477:226;;;;;;:::i;:::-;;:::i;99797:51::-;;;;;;99588:59;;;;;;100043:28;;;;;;:::i;:::-;;:::i;102702:24::-;;;;;;;;;145766:474;;;:::i;126797:720::-;126918:12;:19;126851:27;;126904:34;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;126904:34:0;-1:-1:-1;126953:26:0;;;;;;;:17;:26;;;;;;126891:47;;-1:-1:-1;126953:31:0;126949:559;;127005:9;127000:103;127024:12;:19;127020:23;;127000:103;;;127086:1;127070:10;127081:1;127070:13;;;;;;;;:::i;:::-;;;;;;;;;;:17;127045:3;;127000:103;;;;126797:720;;;:::o;126949:559::-;127144:36;127183:16;:14;:16::i;:::-;127144:55;;127268:9;127263:234;127287:12;:19;127283:23;;127263:234;;;127461:16;;;;;;;:7;:16;;;;;;;;:19;;;;;;;;;127408:32;;;:23;:32;;;;;:35;;;;;;;;;127381:22;;127349:132;;127461:19;127349:107;;127451:4;;127350:95;;127381:63;;127408:35;127381:19;;127478:1;;127381:22;;;;;;:::i;:::-;;;;;;;:26;;:63;;;;:::i;:::-;127350:26;;;;;;;:17;:26;;;;;;;:30;:95::i;:::-;127349:101;;:107::i;:::-;:111;;:132::i;:::-;127333:10;127344:1;127333:13;;;;;;;;:::i;:::-;;;;;;;;;;:148;127308:3;;127263:234;;;;127129:379;126949:559;126797:720;;;:::o;152732:113::-;104564:5;;;;104550:10;:19;;:52;;-1:-1:-1;104587:15:0;;;;104573:10;:29;104550:52;104542:86;;;;;;;8140:2:1;104542:86:0;;;8122:21:1;8179:2;8159:18;;;8152:30;8218:23;8198:18;;;8191:51;8259:18;;104542:86:0;;;;;;;;;152807:5:::1;:30:::0;;;::::1;;::::0;;;::::1;::::0;;;::::1;::::0;;152732:113::o;109765:222::-;109874:19;;109939:28;;109824:7;;109851:127;;109909:26;109874:19;109909:4;:26;:::i;:::-;109908:59;;;;:::i;:::-;109851:8;:127::i;:::-;109844:134;109765:222;-1:-1:-1;;109765:222:0:o;34855:141::-;35335:5;;;;35321:10;:19;35313:79;;;;;;;9131:2:1;35313:79:0;;;9113:21:1;9170:2;9150:18;;;9143:30;9209:34;9189:18;;;9182:62;9280:17;9260:18;;;9253:45;9315:19;;35313:79:0;8929:411:1;35313:79:0;34927:14:::1;:23:::0;;;::::1;;::::0;::::1;::::0;;::::1;::::0;;;34966:22:::1;::::0;1556:74:1;;;34966:22:0::1;::::0;1544:2:1;1529:18;34966:22:0::1;;;;;;;34855:141:::0;:::o;146389:242::-;104792:5;;;;104778:10;:19;;:52;;-1:-1:-1;104815:15:0;;;;104801:10;:29;104778:52;:87;;;-1:-1:-1;104848:17:0;;;;104834:10;:31;104778:87;104770:122;;;;;;;9547:2:1;104770:122:0;;;9529:21:1;9586:2;9566:18;;;9559:30;9625:24;9605:18;;;9598:52;9667:18;;104770:122:0;9345:346:1;104770:122:0;146465:13:::1;::::0;;;::::1;;;146464:14;146456:46;;;::::0;::::1;::::0;;9898:2:1;146456:46:0::1;::::0;::::1;9880:21:1::0;9937:2;9917:18;;;9910:30;9976:21;9956:18;;;9949:49;10015:18;;146456:46:0::1;9696:343:1::0;146456:46:0::1;146513:13;:20:::0;;;::::1;::::0;::::1;::::0;;146576:6:::1;:4;:6::i;:::-;146600:23;::::0;::::1;::::0;;;::::1;146389:242::o:0;136341:163::-;38872:1;39478:7;;:19;39470:63;;;;;;;10246:2:1;39470:63:0;;;10228:21:1;10285:2;10265:18;;;10258:30;10324:33;10304:18;;;10297:61;10375:18;;39470:63:0;10044:355:1;39470:63:0;38872:1;39611:18;;136426:70:::1;136439:10;::::0;136463:9;136474:4;136480:15:::1;136426:12;:70::i;:::-;-1:-1:-1::0;;38828:1:0;39790:7;:22;136341:163::o;148162:261::-;104564:5;;;;104550:10;:19;;:52;;-1:-1:-1;104587:15:0;;;;104573:10;:29;104550:52;104542:86;;;;;;;8140:2:1;104542:86:0;;;8122:21:1;8179:2;8159:18;;;8152:30;8218:23;8198:18;;;8191:51;8259:18;;104542:86:0;7938:345:1;104542:86:0;148253:33:::1;::::0;::::1;;::::0;;;:15:::1;:33;::::0;;;;;::::1;;:41;;:33:::0;:41:::1;148245:73;;;::::0;::::1;::::0;;10606:2:1;148245:73:0::1;::::0;::::1;10588:21:1::0;10645:2;10625:18;;;10618:30;10684:21;10664:18;;;10657:49;10723:18;;148245:73:0::1;10404:343:1::0;148245:73:0::1;148382:33;;;::::0;;;:15:::1;:33;::::0;;;;148375:40;;;::::1;::::0;;148162:261::o;127683:322::-;127827:12;:19;127738:38;;127813:34;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;127813:34:0;;127789:58;;127863:9;127858:140;127882:12;:19;127878:23;;127858:140;;;127951:35;127970:15;;127951:11;127963:1;127951:14;;;;;;;;:::i;:::-;;;;;;;;;:18;;:35;;;;:::i;:::-;127924:21;127946:1;127924:24;;;;;;;;:::i;:::-;;;;;;;;;;:62;127903:3;;127858:140;;;;127683:322;:::o;109457:133::-;109561:21;;;;;;;:12;:21;;;;;;;;109554:28;;;;;;;;;;;;;;;;;109521:20;;109554:28;;109561:21;;109554:28;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;109457:133;;;:::o;146975:357::-;105002:12;;;;:20;;:12;:20;104994:49;;;;;;;10954:2:1;104994:49:0;;;10936:21:1;10993:2;10973:18;;;10966:30;11032:18;11012;;;11005:46;11068:18;;104994:49:0;10752:340:1;104994:49:0;147128:40:::1;::::0;::::1;;::::0;;;:24:::1;:40;::::0;;;;;;;147169:10:::1;147128:52:::0;;;;;;;;::::1;;:83:::0;::::1;;;-1:-1:-1::0;147200:10:0::1;147184:27;::::0;;;:15:::1;:27;::::0;;;;;::::1;;147128:83;147120:122;;;::::0;::::1;::::0;;11299:2:1;147120:122:0::1;::::0;::::1;11281:21:1::0;11338:2;11318:18;;;11311:30;11377:28;11357:18;;;11350:56;11423:18;;147120:122:0::1;11097:350:1::0;147120:122:0::1;147253:71;147266:14;147282:10;147294:6;147302:4;147308:15;147253:12;:71::i;:::-;146975:357:::0;;;;:::o;119451:1055::-;119546:5;;119514:7;;119538:28;119546:5;119538:28;119534:964;;119744:34;119781:28;119801:7;119781:19;:28::i;:::-;119744:65;-1:-1:-1;119828:30:0;;119824:570;;119910:5;;:24;;;;;:5;1574:55:1;;;119910:24:0;;;1556:74:1;119879:27:0;;119909:84;;119966:26;;119909:52;;98690:4;;119910:5;;;:15;;1529:18:1;;119910:24:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;119909:30;;:52::i;:84::-;119879:114;;120030:24;120057:75;98690:4;120058:47;120084:20;;120059:19;120058:25;;:47;;;;:::i;120057:75::-;120030:102;;120238:20;;120219:16;:39;120215:84;;;-1:-1:-1;120279:20:0;;120215:84;120327:16;119451:1055;-1:-1:-1;;;;119451:1055:0:o;119824:570::-;-1:-1:-1;120393:1:0;;119451:1055;-1:-1:-1;;119451:1055:0:o;119534:964::-;-1:-1:-1;120497:1:0;;119451:1055;-1:-1:-1;119451:1055:0:o;151686:96::-;104564:5;;;;104550:10;:19;;:52;;-1:-1:-1;104587:15:0;;;;104573:10;:29;104550:52;104542:86;;;;;;;8140:2:1;104542:86:0;;;8122:21:1;8179:2;8159:18;;;8152:30;8218:23;8198:18;;;8191:51;8259:18;;104542:86:0;7938:345:1;104542:86:0;151761:13:::1;::::0;;151744:30;;::::1;151761:13:::0;;;;::::1;;;151760:14;151744:30:::0;;::::1;;::::0;;151686:96::o;141754:210::-;141806:16;38872:1;39478:7;;:19;39470:63;;;;;;;10246:2:1;39470:63:0;;;10228:21:1;10285:2;10265:18;;;10258:30;10324:33;10304:18;;;10297:61;10375:18;;39470:63:0;10044:355:1;39470:63:0;38872:1;39611:18;;141843:23:::1;::::0;;;::::1;;;:32;141835:69;;;::::0;::::1;::::0;;11843:2:1;141835:69:0::1;::::0;::::1;11825:21:1::0;11882:2;11862:18;;;11855:30;11921:27;11901:18;;;11894:55;11966:18;;141835:69:0::1;11641:349:1::0;141835:69:0::1;141922:34;141933:10;141945;141922;:34::i;:::-;141915:41;;38828:1:::0;39790:7;:22;141754:210;:::o;156456:46::-;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;119116:187::-;119183:7;119210:85;98690:4;119210:59;119240:28;;119211:23;119226:7;119211:14;:23::i;103711:31::-;;;;;;;:::i;110429:8163::-;110476:7;110557:25;115381:27;115667:17;115686;115710:12;;;;;;;;;;;:24;;;:26;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;115756:14:0;;115666:71;;;;;-1:-1:-1;115666:71:0;;;-1:-1:-1;115756:14:0;;115752:102;;;115794:9;115772:31;;115752:102;;;115845:9;115823:31;;115752:102;115922:12;;;;;;;;;;;:24;;;:26;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;115892;:19;115914:4;115892:26;:::i;:::-;115891:57;;;;:::i;:::-;115871:77;-1:-1:-1;116069:22:0;116090:1;115871:77;116069:22;:::i;:::-;;110429:8163;-1:-1:-1;;;;;110429:8163:0:o;151521:112::-;104564:5;;;;104550:10;:19;;:52;;-1:-1:-1;104587:15:0;;;;104573:10;:29;104550:52;104542:86;;;;;;;8140:2:1;104542:86:0;;;8122:21:1;8179:2;8159:18;;;8152:30;8218:23;8198:18;;;8191:51;8259:18;;104542:86:0;7938:345:1;104542:86:0;151596:22:::1;:29:::0;;;::::1;::::0;::::1;::::0;;151521:112::o;149608:796::-;104564:5;;;;104550:10;:19;;:52;;-1:-1:-1;104587:15:0;;;;104573:10;:29;104550:52;104542:86;;;;;;;8140:2:1;104542:86:0;;;8122:21:1;8179:2;8159:18;;;8152:30;8218:23;8198:18;;;8191:51;8259:18;;104542:86:0;7938:345:1;104542:86:0;98690:4:::1;149773:20;:44;;149765:93;;;::::0;::::1;::::0;;13287:2:1;149765:93:0::1;::::0;::::1;13269:21:1::0;13326:2;13306:18;;;13299:30;13365:34;13345:18;;;13338:62;13436:6;13416:18;;;13409:34;13460:19;;149765:93:0::1;13085:400:1::0;149765:93:0::1;149981:1;149949:29;:33;149941:72;;;::::0;::::1;::::0;;14043:2:1;149941:72:0::1;::::0;::::1;14025:21:1::0;14082:2;14062:18;;;14055:30;14121:28;14101:18;;;14094:56;14167:18;;149941:72:0::1;13841:350:1::0;149941:72:0::1;150026:19;:42:::0;;;150079:20:::1;:44:::0;;;150134:28:::1;:60:::0;;;150212:40:::1;::::0;1374:25:1;;;150212:40:0::1;::::0;1362:2:1;1347:18;150212:40:0::1;;;;;;;150268:52;150300:19;;150268:52;;;;1374:25:1::0;;1362:2;1347:18;;1228:177;150268:52:0::1;;;;;;;;150336:60;150367:28;;150336:60;;;;1374:25:1::0;;1362:2;1347:18;;1228:177;150336:60:0::1;;;;;;;;149608:796:::0;;;:::o;120768:2692::-;120959:21;;;120857:32;120959:21;;;:12;:21;;;;;:32;;120857;;120959:21;120981:9;;120959:32;;;;;;:::i;:::-;;;;;;;;;120928:63;;;;;;;;120959:32;;;;;;;120928:63;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;121174:28;;;;;:19;:28;;;;;;120928:63;;-1:-1:-1;;121170:224:0;;;-1:-1:-1;121267:25:0;;;;121170:224;;;-1:-1:-1;121354:28:0;;;;;;;:19;:28;;;;;;121170:224;121483:15;121453:9;:26;;;:45;121449:1802;;121678:26;;;;121647:28;;;;;;;:19;:28;;;;;;:57;121643:1087;;;121724:26;121782:17;121753:9;:26;;;:46;;;;:::i;:::-;121724:75;;121818:25;121864:9;:26;;;121846:15;:44;;;;:::i;:::-;121818:72;-1:-1:-1;121970:33:0;122006:38;122021:22;122042:1;122021:18;:22;:::i;122006:38::-;121970:74;-1:-1:-1;122261:17:0;122333:21;122337:17;122261;122333:21;:::i;:::-;122282:46;122310:18;122282:25;:46;:::i;:::-;122281:74;;;;:::i;:::-;122261:94;-1:-1:-1;122414:38:0;122435:17;122414:18;:38;:::i;:::-;122401:52;;:9;:52;:::i;:::-;122374:79;;121705:764;;;;121449:1802;;121643:1087;122713:1;122686:28;;121449:1802;;;122875:21;122930:20;122982:17;122953:9;:26;;;:46;;;;:::i;:::-;122930:69;;123018:20;123070:15;123041:9;:26;;;:44;;;;:::i;:::-;123018:67;-1:-1:-1;123152:1:0;123121:27;123018:67;123121:12;:27;:::i;:::-;123120:33;;;;:::i;:::-;123104:49;;122911:258;;123210:29;123225:13;123210:14;:29::i;:::-;123183:56;;122795:456;121449:1802;123373:9;:25;;;123346:24;:52;123342:110;;;123427:9;:25;;;123400:52;;123342:110;120891:2569;;120768:2692;;;;:::o;102278:53::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;102278:53:0;;-1:-1:-1;102278:53:0;;;:::o;35004:271::-;35073:14;;;;35059:10;:28;35051:94;;;;;;;14661:2:1;35051:94:0;;;14643:21:1;14700:2;14680:18;;;14673:30;14739:34;14719:18;;;14712:62;14810:23;14790:18;;;14783:51;14851:19;;35051:94:0;14459:417:1;35051:94:0;35174:5;;;35181:14;35161:35;;;35174:5;;;;15116:34:1;;35181:14:0;;;;15181:2:1;15166:18;;15159:43;35161:35:0;;15028:18:1;35161:35:0;;;;;;;35215:14;;;;35207:22;;;;;;35215:14;;;35207:22;;;;35240:27;;;35004:271::o;152009:126::-;104564:5;;;;104550:10;:19;;:52;;-1:-1:-1;104587:15:0;;;;104573:10;:29;104550:52;104542:86;;;;;;;8140:2:1;104542:86:0;;;8122:21:1;8179:2;8159:18;;;8152:30;8218:23;8198:18;;;8191:51;8259:18;;104542:86:0;7938:345:1;104542:86:0;152104:23:::1;::::0;;152077:50;;::::1;152104:23:::0;;;;::::1;;;152103:24;152077:50:::0;;::::1;;::::0;;152009:126::o;95475:29::-;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;95475:29:0;:::o;100843:28::-;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;100843:28:0;:::o;148667:553::-;104564:5;;;;104550:10;:19;;:52;;-1:-1:-1;104587:15:0;;;;104573:10;:29;104550:52;104542:86;;;;;;;8140:2:1;104542:86:0;;;8122:21:1;8179:2;8159:18;;;8152:30;8218:23;8198:18;;;8191:51;8259:18;;104542:86:0;7938:345:1;104542:86:0;148866:12:::1;::::0;::::1;;148862:164;;148926:12;::::0;::::1;::::0;;::::1;148902:37:::0;;::::1;::::0;148894:66:::1;;;::::0;::::1;::::0;;10954:2:1;148894:66:0::1;::::0;::::1;10936:21:1::0;10993:2;10973:18;;;10966:30;11032:18;11012;;;11005:46;11068:18;;148894:66:0::1;10752:340:1::0;148894:66:0::1;149141:5;::::0;149112:48:::1;::::0;;;;:28:::1;149141:5:::0;;::::1;149112:48;::::0;::::1;15387:74:1::0;15477:18;;;15470:34;;;149112:28:0;;::::1;::::0;::::1;::::0;15360:18:1;;149112:48:0::1;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1::0;149176:36:0::1;::::0;;15417:42:1;15405:55;;15387:74;;15492:2;15477:18;;15470:34;;;149176:36:0::1;::::0;15360:18:1;149176:36:0::1;;;;;;;;148667:553:::0;;:::o;123785:1952::-;124079:26;;;123877:27;124079:26;;;:17;:26;;;;;;;123877:27;124266:24;124097:7;124266:15;:24::i;:::-;124366:26;;;124303:33;124366:26;;;:17;:26;;;;;;124243:47;;-1:-1:-1;124303:33:0;124366:31;:66;;;;-1:-1:-1;124401:26:0;;;;;;;:17;:26;;;;;;:31;124366:66;124365:143;;;-1:-1:-1;124476:31:0;;;;;;;:22;:31;;;;;;124452:55;;;124365:143;124347:638;;;-1:-1:-1;124749:20:0;124347:638;;;124937:31;;;;;;;:22;:31;;;;;;124972:1;;124914:54;;:20;:54;:::i;:::-;124913:60;;;;:::i;:::-;124885:88;;124347:638;125120:1;125098:23;;125137:9;125132:598;125156:21;;;;;;;:12;:21;;;;;:28;125152:32;;125132:598;;;125237:21;;;125206:28;125237:21;;;:12;:21;;;;;:24;;125259:1;;125237:24;;;;;;:::i;:::-;;;;;;;;;;;125206:55;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;125333:32;125368:34;125391:7;125400:1;125368:22;:34::i;:::-;125484:19;;;;125333:69;;-1:-1:-1;125464:17:0;98690:4;125579:52;125606:25;125333:69;125579:52;:::i;:::-;125566:66;;:9;:66;:::i;:::-;125565:91;;;;:::i;:::-;125552:105;;:9;:105;:::i;:::-;125518:139;-1:-1:-1;125672:46:0;125518:139;125672:46;;:::i;:::-;;-1:-1:-1;;125186:3:0;;;;;-1:-1:-1;125132:598:0;;-1:-1:-1;;125132:598:0;;;124006:1731;123785:1952;;;;;:::o;139065:251::-;38872:1;39478:7;;:19;39470:63;;;;;;;10246:2:1;39470:63:0;;;10228:21:1;10285:2;10265:18;;;10258:30;10324:33;10304:18;;;10297:61;10375:18;;39470:63:0;10044:355:1;39470:63:0;38872:1;39611:18;;139175:17:::1;::::0;;;::::1;;;:26;139167:57;;;::::0;::::1;::::0;;15967:2:1;139167:57:0::1;::::0;::::1;15949:21:1::0;16006:2;15986:18;;;15979:30;16045:20;16025:18;;;16018:48;16083:18;;139167:57:0::1;15765:342:1::0;139167:57:0::1;139235:73;139251:10;139263;139275:6;139283:24;139235:15;:73::i;152498:130::-:0;104564:5;;;;104550:10;:19;;:52;;-1:-1:-1;104587:15:0;;;;104573:10;:29;104550:52;104542:86;;;;;;;8140:2:1;104542:86:0;;;8122:21:1;8179:2;8159:18;;;8152:30;8218:23;8198:18;;;8191:51;8259:18;;104542:86:0;7938:345:1;104542:86:0;152582:17:::1;:38:::0;;;::::1;;::::0;;;::::1;::::0;;;::::1;::::0;;152498:130::o;147921:128::-;104564:5;;;;104550:10;:19;;:52;;-1:-1:-1;104587:15:0;;;;104573:10;:29;104550:52;104542:86;;;;;;;8140:2:1;104542:86:0;;;8122:21:1;8179:2;8159:18;;;8152:30;8218:23;8198:18;;;8191:51;8259:18;;104542:86:0;7938:345:1;104542:86:0;148001:33:::1;;;::::0;;;:15:::1;:33;::::0;;;;:40;;;::::1;148037:4;148001:40;::::0;;147921:128::o;151377:97::-;104564:5;;;;104550:10;:19;;:52;;-1:-1:-1;104587:15:0;;;;104573:10;:29;104550:52;104542:86;;;;;;;8140:2:1;104542:86:0;;;8122:21:1;8179:2;8159:18;;;8152:30;8218:23;8198:18;;;8191:51;8259:18;;104542:86:0;7938:345:1;104542:86:0;151454:12:::1;::::0;;151438:28;;::::1;151454:12;::::0;;::::1;151453:13;151438:28;::::0;;151377:97::o;100731:28::-;;;;;;;;;;;;150618:537;104564:5;;;;104550:10;:19;;:52;;-1:-1:-1;104587:15:0;;;;104573:10;:29;104550:52;104542:86;;;;;;;8140:2:1;104542:86:0;;;8122:21:1;8179:2;8159:18;;;8152:30;8218:23;8198:18;;;8191:51;8259:18;;104542:86:0;7938:345:1;104542:86:0;150805:1:::1;150772:29;:34;;150764:72;;;::::0;::::1;::::0;;16314:2:1;150764:72:0::1;::::0;::::1;16296:21:1::0;16353:2;16333:18;;;16326:30;16392:27;16372:18;;;16365:55;16437:18;;150764:72:0::1;16112:349:1::0;150764:72:0::1;150873:1;150855:14;:19;;150847:57;;;::::0;::::1;::::0;;16668:2:1;150847:57:0::1;::::0;::::1;16650:21:1::0;16707:2;16687:18;;;16680:30;16746:27;16726:18;;;16719:55;16791:18;;150847:57:0::1;16466:349:1::0;150847:57:0::1;150917:28;:60:::0;;;150988:13:::1;:30:::0;;;151036:61:::1;::::0;1374:25:1;;;151036:61:0::1;::::0;1362:2:1;1347:18;151036:61:0::1;;;;;;;151113:34;::::0;1374:25:1;;;151113:34:0::1;::::0;1362:2:1;1347:18;151113:34:0::1;1228:177:1::0;131439:1445:0;38872:1;39478:7;;:19;39470:63;;;;;;;10246:2:1;39470:63:0;;;10228:21:1;10285:2;10265:18;;;10258:30;10324:33;10304:18;;;10297:61;10375:18;;39470:63:0;10044:355:1;39470:63:0;38872:1;39611:18;;131580:13:::1;::::0;;;::::1;;;131579:14;131571:41;;;::::0;::::1;::::0;;17022:2:1;131571:41:0::1;::::0;::::1;17004:21:1::0;17061:2;17041:18;;;17034:30;17100:16;17080:18;;;17073:44;17134:18;;131571:41:0::1;16820:338:1::0;131571:41:0::1;131680:22;::::0;;;::::1;;;131679:23;131671:60;;;::::0;::::1;::::0;;17365:2:1;131671:60:0::1;::::0;::::1;17347:21:1::0;17404:2;17384:18;;;17377:30;17443:26;17423:18;;;17416:54;17487:18;;131671:60:0::1;17163:348:1::0;131671:60:0::1;131795:34;131806:10;131818;131795;:34::i;:::-;;131891:28;131921:21:::0;131946:29:::1;131956:10;131968:6;131946:9;:29::i;:::-;131890:85;;;;132025:15;132065:8;132043:9;:19;;;:30;;;;:::i;:::-;132025:48:::0;-1:-1:-1;132243:12:0::1;::::0;132203:91:::1;::::0;132243:12:::1;;132258:10;132278:4;132285:8:::0;132203:31:::1;:91::i;:::-;132378:186;::::0;;::::1;::::0;::::1;::::0;;;;;::::1;132425:25:::0;;::::1;::::0;132378:186;;::::1;::::0;;;;;;;;132487:26;;::::1;::::0;132378:186;;;;;132528:25;;::::1;::::0;132378:186;;;;132349:10:::1;-1:-1:-1::0;132336:24:0;;;:12:::1;:24:::0;;;;;;;:39;;132361:13;;132336:39;::::1;;;;;:::i;:::-;;;;;;;;;;;:228;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;132635:8;132608:23;;:35;;;;;;;:::i;:::-;::::0;;;-1:-1:-1;;132672:10:0::1;132654:29;::::0;;;:17:::1;:29;::::0;;;;:41;;132687:8;;132654:29;:41:::1;::::0;132687:8;;132654:41:::1;:::i;:::-;::::0;;;-1:-1:-1;132764:48:0::1;::::0;-1:-1:-1;132788:10:0::1;132800:5;132807:4;132764:23;:48::i;:::-;132830:46;::::0;;18034:25:1;;;18090:2;18075:18;;18068:34;;;132847:10:0::1;::::0;132830:46:::1;::::0;18007:18:1;132830:46:0::1;;;;;;;-1:-1:-1::0;;38828:1:0;39790:7;:22;-1:-1:-1;;;131439:1445:0:o;152254:116::-;104564:5;;;;104550:10;:19;;:52;;-1:-1:-1;104587:15:0;;;;104573:10;:29;104550:52;104542:86;;;;;;;8140:2:1;104542:86:0;;;8122:21:1;8179:2;8159:18;;;8152:30;8218:23;8198:18;;;8191:51;8259:18;;104542:86:0;7938:345:1;104542:86:0;152331:15:::1;:31:::0;;;::::1;;::::0;;;::::1;::::0;;;::::1;::::0;;152254:116::o;125884:704::-;126028:12;:19;125931:42;;126014:34;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;126014:34:0;;125986:62;;126063:23;;126090:1;126063:28;:59;;;-1:-1:-1;126095:22:0;;:27;126063:59;126059:520;;;126167:21;126139:49;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;125884:704;:::o;126059:520::-;126282:9;126277:291;126301:12;:19;126297:23;;126277:291;;;126378:174;126429:104;126510:22;;126429:76;126500:4;126429:66;126480:11;126492:1;126480:14;;;;;;;;:::i;:::-;;;;;;;;;126429:46;126460:14;;126429:26;:24;:26::i;:::-;:30;;:46::i;:104::-;126378:21;126400:1;126378:24;;;;;;;;:::i;:::-;;;;;;;;;:28;;:174;;;;:::i;:::-;126347:25;126373:1;126347:28;;;;;;;;:::i;:::-;;;;;;;;;;:205;126322:3;;126277:291;;151838:108;104564:5;;;;104550:10;:19;;:52;;-1:-1:-1;104587:15:0;;;;104573:10;:29;104550:52;104542:86;;;;;;;8140:2:1;104542:86:0;;;8122:21:1;8179:2;8159:18;;;8152:30;8218:23;8198:18;;;8191:51;8259:18;;104542:86:0;7938:345:1;104542:86:0;151921:17:::1;::::0;;151900:38;;::::1;151921:17:::0;;;;::::1;;;151920:18;151900:38:::0;;::::1;;::::0;;151838:108::o;133117:1642::-;38872:1;39478:7;;:19;39470:63;;;;;;;10246:2:1;39470:63:0;;;10228:21:1;10285:2;10265:18;;;10258:30;10324:33;10304:18;;;10297:61;10375:18;;39470:63:0;10044:355:1;39470:63:0;38872:1;39611:18;;133259:13:::1;::::0;;;::::1;;;133258:14;133250:41;;;::::0;::::1;::::0;;17022:2:1;133250:41:0::1;::::0;::::1;17004:21:1::0;17061:2;17041:18;;;17034:30;17100:16;17080:18;;;17073:44;17134:18;;133250:41:0::1;16820:338:1::0;133250:41:0::1;133359:22;::::0;;;::::1;;;133358:23;133350:60;;;::::0;::::1;::::0;;17365:2:1;133350:60:0::1;::::0;::::1;17347:21:1::0;17404:2;17384:18;;;17377:30;17443:26;17423:18;;;17416:54;17487:18;;133350:60:0::1;17163:348:1::0;133350:60:0::1;133474:34;133485:10;133497;133474;:34::i;:::-;;133570:28;133600:21:::0;133625:29:::1;133635:10;133647:6;133625:9;:29::i;:::-;133569:85;;;;133709:15;133693:13;:31;133685:65;;;::::0;::::1;::::0;;18315:2:1;133685:65:0::1;::::0;::::1;18297:21:1::0;18354:2;18334:18;;;18327:30;18393:23;18373:18;;;18366:51;18434:18;;133685:65:0::1;18113:345:1::0;133685:65:0::1;133796:17;133846:15;133817:9;:26;;;:44;133816:97;;133912:1;133816:97;;;133894:15;133865:9;:26;;;:44;;;;:::i;:::-;133796:117:::0;-1:-1:-1;133924:16:0::1;133943:31;133959:15;133943:13:::0;:31:::1;:::i;:::-;133924:50;;134080:9;134069:8;:20;134061:57;;;::::0;::::1;::::0;;18665:2:1;134061:57:0::1;::::0;::::1;18647:21:1::0;18704:2;18684:18;;;18677:30;18743:26;18723:18;;;18716:54;18787:18;;134061:57:0::1;18463:348:1::0;134061:57:0::1;134149:13;;134137:8;:25;;134129:64;;;::::0;::::1;::::0;;19018:2:1;134129:64:0::1;::::0;::::1;19000:21:1::0;19057:2;19037:18;;;19030:30;19096:28;19076:18;;;19069:56;19142:18;;134129:64:0::1;18816:350:1::0;134129:64:0::1;134224:28;;134212:8;:40;;134204:80;;;::::0;::::1;::::0;;19373:2:1;134204:80:0::1;::::0;::::1;19355:21:1::0;19412:2;19392:18;;;19385:30;19451:29;19431:18;;;19424:57;19498:18;;134204:80:0::1;19171:351:1::0;134204:80:0::1;134368:174;;;;;;;;134394:6;134368:174;;;;134415:15;134368:174;;;;134445:9;:19;;;134368:174;;;;134479:13;134368:174;;;;134507:24;134522:8;134507:14;:24::i;:::-;134368:174:::0;;134339:10:::1;134326:24;::::0;;;:12:::1;:24;::::0;;;;:39;;134351:13;;134326:39;::::1;;;;;:::i;:::-;;;;;;;;;;;:216;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;134611:48;134635:10;134647:5;134654:4;134611:23;:48::i;:::-;134677:74;::::0;;19758:25:1;;;19814:2;19799:18;;19792:34;;;134720:15:0::1;19842:18:1::0;;;19835:34;19900:2;19885:18;;19878:34;;;134677:74:0;;134690:10:::1;::::0;134677:74:::1;::::0;;;;;19745:3:1;134677:74:0;;::::1;-1:-1:-1::0;;38828:1:0;39790:7;:22;-1:-1:-1;;;;133117:1642:0:o;118740:157::-;118852:26;;;118802:7;118852:26;;;:17;:26;;;;;;118829:60;;118884:4;;118829:50;;118830:16;:14;:16::i;151227:97::-;104564:5;;;;104550:10;:19;;:52;;-1:-1:-1;104587:15:0;;;;104573:10;:29;104550:52;104542:86;;;;;;;8140:2:1;104542:86:0;;;8122:21:1;8179:2;8159:18;;;8152:30;8218:23;8198:18;;;8191:51;8259:18;;104542:86:0;7938:345:1;104542:86:0;151302:14:::1;::::0;;151284:32;;::::1;151302:14;::::0;;;::::1;;;151301:15;151284:32:::0;;::::1;;::::0;;151227:97::o;147496:304::-;105002:12;;;;:20;;:12;:20;104994:49;;;;;;;10954:2:1;104994:49:0;;;10936:21:1;10993:2;10973:18;;;10966:30;11032:18;11012;;;11005:46;11068:18;;104994:49:0;10752:340:1;104994:49:0;147610:40:::1;::::0;::::1;;::::0;;;:24:::1;:40;::::0;;;;;;;147651:10:::1;147610:52:::0;;;;;;;;::::1;;:83:::0;::::1;;;-1:-1:-1::0;147682:10:0::1;147666:27;::::0;;;:15:::1;:27;::::0;;;;;::::1;;147610:83;147602:122;;;::::0;::::1;::::0;;11299:2:1;147602:122:0::1;::::0;::::1;11281:21:1::0;11338:2;11318:18;;;11311:30;11377:28;11357:18;;;11350:56;11423:18;;147602:122:0::1;11097:350:1::0;147602:122:0::1;147735:57;147751:14;147767:10;147779:6;147787:4;147735:15;:57::i;:::-;147496:304:::0;;:::o;135477:226::-;135560:33;;;;;;;:15;:33;;;;;;;;135552:70;;;;;;;20125:2:1;135552:70:0;;;20107:21:1;20164:2;20144:18;;;20137:30;20203:26;20183:18;;;20176:54;20247:18;;135552:70:0;19923:348:1;135552:70:0;135658:10;135633:36;;;;:24;:36;;;;;;;;;:54;;;;;;;;;;:61;;;;135690:4;135633:61;;;135477:226::o;100043:28::-;;;;;;;;;;;;145766:474;145808:13;;;;;;;145800:50;;;;;;;20478:2:1;145800:50:0;;;20460:21:1;20517:2;20497:18;;;20490:30;20556:26;20536:18;;;20529:54;20600:18;;145800:50:0;20276:348:1;145800:50:0;145918:22;;;;;;;145917:23;145909:60;;;;;;;17365:2:1;145909:60:0;;;17347:21:1;17404:2;17384:18;;;17377:30;17443:26;17423:18;;;17416:54;17487:18;;145909:60:0;17163:348:1;145909:60:0;146068:13;:11;:13::i;:::-;146153:15;146136:14;:32;;;146216:15;;146194:38;;146153:15;146194:21;:38::i;:::-;146179:12;:53;145766:474::o;2522:136::-;2580:7;2607:43;2611:1;2614;2607:43;;;;;;;;;;;;;;;;;:3;:43::i;:::-;2600:50;2522:136;-1:-1:-1;;;2522:136:0:o;3438:471::-;3496:7;3741:1;3746;3741:6;3737:47;;-1:-1:-1;3771:1:0;3764:8;;3737:47;3796:9;3808:5;3812:1;3808;:5;:::i;:::-;3796:17;-1:-1:-1;3841:1:0;3832:5;3836:1;3796:17;3832:5;:::i;:::-;:10;3824:56;;;;;;;20831:2:1;3824:56:0;;;20813:21:1;20870:2;20850:18;;;20843:30;20909:34;20889:18;;;20882:62;20980:3;20960:18;;;20953:31;21001:19;;3824:56:0;20629:397:1;4377:132:0;4435:7;4462:39;4466:1;4469;4462:39;;;;;;;;;;;;;;;;;:3;:39::i;2066:181::-;2124:7;;2156:5;2160:1;2156;:5;:::i;:::-;2144:17;;2185:1;2180;:6;;2172:46;;;;;;;21233:2:1;2172:46:0;;;21215:21:1;21272:2;21252:18;;;21245:30;21311:29;21291:18;;;21284:57;21358:18;;2172:46:0;21031:351:1;33575:106:0;33633:7;33664:1;33660;:5;:13;;33672:1;33660:13;;;-1:-1:-1;33668:1:0;;33575:106;-1:-1:-1;33575:106:0:o;137120:1619::-;137335:14;137351:4;105345:49;105369:7;105378:8;105388:5;105345:23;:49::i;:::-;137377:13:::1;::::0;;;::::1;;;137376:14;::::0;:53:::1;;-1:-1:-1::0;137410:10:0::1;137394:27;::::0;;;:15:::1;:27;::::0;;;;;::::1;;:35;;:27:::0;:35:::1;137376:53;137368:96;;;::::0;::::1;::::0;;21589:2:1;137368:96:0::1;::::0;::::1;21571:21:1::0;21628:2;21608:18;;;21601:30;21667:32;21647:18;;;21640:60;21717:18;;137368:96:0::1;21387:354:1::0;137368:96:0::1;137484:22;::::0;;;::::1;;;137483:23;137475:60;;;::::0;::::1;::::0;;17365:2:1;137475:60:0::1;::::0;::::1;17347:21:1::0;17404:2;17384:18;;;17377:30;17443:26;17423:18;;;17416:54;17487:18;;137475:60:0::1;17163:348:1::0;137475:60:0::1;137566:1;137554:9;:13;137546:51;;;::::0;::::1;::::0;;21948:2:1;137546:51:0::1;::::0;::::1;21930:21:1::0;21987:2;21967:18;;;21960:30;22026:27;22006:18;;;21999:55;22071:18;;137546:51:0::1;21746:349:1::0;137546:51:0::1;137624:13;;137616:4;:21;;137608:60;;;::::0;::::1;::::0;;19018:2:1;137608:60:0::1;::::0;::::1;19000:21:1::0;19057:2;19037:18;;;19030:30;19096:28;19076:18;;;19069:56;19142:18;;137608:60:0::1;18816:350:1::0;137608:60:0::1;137695:28;;137687:4;:36;;137679:75;;;::::0;::::1;::::0;;19373:2:1;137679:75:0::1;::::0;::::1;19355:21:1::0;19412:2;19392:18;;;19385:30;19451:29;19431:18;;;19424:57;19498:18;;137679:75:0::1;19171:351:1::0;137679:75:0::1;137767:23;137793:20;137808:4;137793:14;:20::i;:::-;137912:33;::::0;::::1;137824:14;137912:33:::0;;;:17:::1;:33;::::0;;;;;;;;137851:95;;22346:66:1;22333:2;22329:15;;;22325:88;137851:95:0;;::::1;22313:101:1::0;;;;22430:12;;;22423:28;;;22467:12;;;22460:28;;;22504:12;;;22497:28;137767:46:0;;-1:-1:-1;137824:14:0;22541:13:1;;137851:95:0::1;::::0;;;;;::::1;::::0;;;;;;137841:106;;137851:95:::1;137841:106:::0;;::::1;::::0;137958:28:::1;::::0;::::1;;::::0;;;:12:::1;:28:::0;;;;;137992:167:::1;::::0;::::1;::::0;;;;;;;::::1;::::0;;;;;;;;;137841:106;;-1:-1:-1;137958:28:0;137992:167;;;138093:25:::1;138039:15:::0;138113:4;138093:19:::1;:25::i;:::-;137992:167:::0;;::::1;::::0;;::::1;::::0;;;137958:202;;::::1;::::0;;::::1;::::0;;-1:-1:-1;137958: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;::::1;::::0;;::::1;::::0;138265:12;138225:96:::1;::::0;138265:12:::1;;138280:14:::0;138304:4:::1;138311:9:::0;138225:31:::1;:96::i;:::-;138391:23;::::0;:38:::1;::::0;138419:9;138391:27:::1;:38::i;:::-;138365:23;:64:::0;138476:33:::1;::::0;::::1;;::::0;;;:17:::1;:33;::::0;;;;;:48:::1;::::0;138514:9;138476:37:::1;:48::i;:::-;138440:33;::::0;::::1;;::::0;;;:17:::1;:33;::::0;;;;:84;;;;138593:52:::1;::::0;138458:14;;138640:4:::1;138593:23;:52::i;:::-;138663:68;::::0;;22796:25:1;;;22852:2;22837:18;;22830:34;;;22880:18;;;22873:34;;;138663:68:0::1;22943:55:1::0;;;22938:2;22923:18;;22916:83;138663:68:0;::::1;::::0;::::1;::::0;22783:3:1;22768:19;138663:68:0::1;;;;;;;137357:1382;;137120:1619:::0;;;;;;;:::o;142354:924::-;142478:28;142453:8;142463:4;105345:49;105369:7;105378:8;105388:5;105345:23;:49::i;:::-;142574:22:::1;::::0;;;::::1;;;142573:23;142565:60;;;::::0;::::1;::::0;;17365:2:1;142565:60:0::1;::::0;::::1;17347:21:1::0;17404:2;17384:18;;;17377:30;17443:26;17423:18;;;17416:54;17487:18;;142565:60:0::1;17163:348:1::0;142565:60:0::1;142674:12;:19:::0;142660:34:::1;::::0;::::1;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;-1:-1:-1;142660:34:0::1;;142646:48;;142710:9;142705:450;142729:12;:19:::0;142725:23;::::1;142705:450;;;142788:17;::::0;::::1;;::::0;;;:7:::1;:17;::::0;;;;;;;:20;;;;;;;;;142771:14;;:11;;142806:1;;142771:14;::::1;;;;;:::i;:::-;;;;;;:37;;;::::0;::::1;142846:1;142829:11;142841:1;142829:14;;;;;;;;:::i;:::-;;;;;;;:18;142825:319;;;142868:17;::::0;::::1;142891:1;142868:17:::0;;;:7:::1;:17;::::0;;;;;;;:20;;;;;;;;:24;142917:12:::1;:15:::0;;142886:1;;142917:15;::::1;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;142911:31;;;142943:19;142964:11;142976:1;142964:14;;;;;;;;:::i;:::-;;;;;;;142911:68;;;;;;;;;;;;;;;15417:42:1::0;15405:55;;;;15387:74;;15492:2;15477:18;;15470:34;15375:2;15360:18;;15213:297;142911:68:0::1;;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;143016:11;143028:1;143016:14;;;;;;;;:::i;:::-;;;;;;;142998:11;143010:1;142998:14;;;;;;;;:::i;:::-;;;;;;;;;:32;;;;;;;:::i;:::-;;;;;;;;143065:8;143054:74;;;143075:11;143087:1;143075:14;;;;;;;;:::i;:::-;;;;;;;143091:12;143104:1;143091:15;;;;;;;;:::i;:::-;;::::0;;;::::1;::::0;;;;::::1;::::0;143054:74:::1;::::0;;23212:25:1;;;143091:15:0::1;::::0;;::::1;23314:18:1::0;;;23307:43;;;;23386:15;;23366:18;;;23359:43;23200:2;23185:18;143054:74:0::1;;;;;;;142825:319;142750:3;;142705:450;;;-1:-1:-1::0;;;143223:29:0::1;::::0;;::::1;;::::0;;;:19:::1;:29;::::0;;;;143255:15:::1;143223:47:::0;;-1:-1:-1;142354:924:0;:::o;139827:1687::-;140229:22;;;;;;;140225:189;;140355:47;140366:14;140382:19;140355:10;:47::i;:::-;;140225:189;140435:28;140465:21;140490:33;140500:14;140516:6;140490:9;:33::i;:::-;140434:89;;;;140561:9;:26;;;140542:15;:45;;:71;;;-1:-1:-1;140591:14:0;;;;;;;;:22;;:14;:22;140542:71;:110;;;-1:-1:-1;140633:10:0;140617:27;;;;:15;:27;;;;;;;;:35;;:27;:35;140542:110;140534:145;;;;;;;23615:2:1;140534:145:0;;;23597:21:1;23654:2;23634:18;;;23627:30;23693:24;23673:18;;;23666:52;23735:18;;140534:145:0;23413:346:1;140534:145:0;140712:19;;;;140748:13;;140744:761;;140839:23;;:38;;140867:9;140839:27;:38::i;:::-;140813:23;:64;140928:33;;;;;;;:17;:33;;;;;;:48;;140966:9;140928:37;:48::i;:::-;140892:33;;;;;;;:17;:33;;;;;;;;:84;;;;141048:12;:28;;;:43;;141077:13;;141048:43;;;;;;:::i;:::-;;;;;;;;;;;;141041:50;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;141168:51;141192:14;141208:4;141214;141168:23;:51::i;:::-;141348:12;;:53;;;;;:12;15405:55:1;;;141348:53:0;;;15387:74:1;15477:18;;;15470:34;;;141348:12:0;;;;:21;;15360:18:1;;141348:53:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;141423:70:0;;;23966:25:1;;;24022:2;24007:18;;24000:34;;;141423:70:0;24070:55:1;;;24050:18;;;24043:83;141423:70:0;;;;;;;;;;;23954:2:1;141423:70:0;;;140744:761;139962:1552;;;139827:1687;;;;:::o;128335:591::-;128417:31;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;128417:31:0;128450:15;128482:11;;128478:348;;128515:9;128510:305;128534:28;;;;;;;:12;:28;;;;;:35;128530:39;;128510:305;;;128610:28;;;;;;;:12;:28;;;;;:31;;128639:1;;128610:31;;;;;;:::i;:::-;;;;;;;;;;;:38;;;128600:6;:48;128596:204;;128687:28;;;;;;;:12;:28;;;;;:31;;128716:1;;128687:31;;;;;;:::i;:::-;;;;;;;;;;;128672:46;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;128751:1;128741:11;;128775:5;;128596:204;128571:3;;128510:305;;;;128478:348;128844:11;;;;;:44;;-1:-1:-1;128859:19:0;;:29;;128844:44;128836:72;;;;;;;24339:2:1;128836:72:0;;;24321:21:1;24378:2;24358:18;;;24351:30;24417:17;24397:18;;;24390:45;24452:18;;128836:72:0;24137:339:1;128836:72:0;128335:591;;;;;:::o;36507:402::-;36732:51;;;36721:10;24762:15:1;;;36732:51:0;;;24744:34:1;24814:15;;;24794:18;;;24787:43;24846:18;;;;24839:34;;;36732:51:0;;;;;;;;;;24656:18:1;;;;36732:51:0;;;;;;;;;;;;;36721:63;;-1:-1:-1;;;;36721:10:0;;;;:63;;36732:51;36721:63;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;36685:99;;;;36803:7;:57;;;;-1:-1:-1;36815:11:0;;:16;;:44;;;36846:4;36835:24;;;;;;;;;;;;:::i;:::-;36795:106;;;;;;;25378:2:1;36795:106:0;;;25360:21:1;25417:2;25397:18;;;25390:30;25456:34;25436:18;;;25429:62;25527:6;25507:18;;;25500:34;25551:19;;36795:106:0;25176:400:1;36795:106:0;36595:314;;36507:402;;;;:::o;129182:2025::-;129368:22;;;;;;;129363:214;;129516:8;129512:54;;;129544:6;:4;:6::i;:::-;129717:19;129713:109;;;129786:24;129802:7;129786:15;:24::i;:::-;129752:31;;;;;;;:22;:31;;;;;:58;129713:109;129838:21;;;;129834:1366;;130052:27;130098:28;130145:27;130190:30;130212:7;130190:21;:30::i;:::-;130340:22;;130030:190;;-1:-1:-1;130030:190:0;;-1:-1:-1;130030:190:0;-1:-1:-1;130340:22:0;;;;;130335:49;;130364:20;130376:7;130364:11;:20::i;:::-;130460:31;;;;;;;:22;:31;;;;;:54;;;130601:42;;;130597:590;;130664:19;130686:44;:19;130710;130686:23;:44::i;:::-;130774:22;;130664:66;;-1:-1:-1;130774:39:0;;130664:66;130774:26;:39::i;:::-;130749:22;:64;130861:36;:19;130885:11;130861:23;:36::i;:::-;130832:26;;;;;;;:17;:26;;;;;:65;-1:-1:-1;130597:590:0;;;130938:19;130960:44;:19;130984;130960:23;:44::i;:::-;131048:22;;130938:66;;-1:-1:-1;131048:39:0;;130938:66;131048:26;:39::i;:::-;131023:22;:64;131135:36;:19;131159:11;131135:23;:36::i;:::-;131106:26;;;;;;;:17;:26;;;;;:65;-1:-1:-1;129861:1339:0;;;129834:1366;129182:2025;;;:::o;110202:133::-;110261:7;110288:39;110297:15;110314:12;;110288:8;:39::i;:::-;110281:46;;110202:133;:::o;143336:2387::-;143468:15;;143449:14;;143427:37;;143428:15;;143427:21;:37::i;:::-;:56;143423:936;;143512:8;;143504:31;143512:8;143504:31;143500:99;;143556:8;;;;;;;;;;;:25;;;:27;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;143500:99;144332:15;144315:14;:32;143423:936;144411:28;144442:64;144451:37;144473:14;;144452:15;144451:21;;:37;;;;:::i;:::-;144490:15;;144442:8;:64::i;:::-;144411:95;;144551:24;144578:16;:14;:16::i;:::-;144551:43;;144610:9;144605:1111;144629:12;:19;144625:23;;144605:1111;;;144724:16;144749:12;144762:1;144749:15;;;;;;;;:::i;:::-;;;;;;;;;;;144743:47;;;;;144784:4;144743:47;;;1556:74:1;144749:15:0;;;;;144743:32;;1529:18:1;;144743:47:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;144724:66;;144955:40;144974:20;144955:11;144967:1;144955:14;;;;;;;;:::i;:40::-;144937:11;144949:1;144937:14;;;;;;;;:::i;:::-;;;;;;;;;:58;;;;;;;:::i;:::-;;;;;;;;145085:7;145093:1;145085:10;;;;;;;;:::i;:::-;;;;;;;145058:21;145080:1;145058:24;;;;;;;;:::i;:::-;;;;;;;;:37;;;;145258:15;145276:34;145295:11;145307:1;145295:14;;;;;;;;:::i;:::-;;;;;;;;;145276:11;145288:1;145276:14;;;;;;;;:::i;:::-;;;;;;;;;:18;;:34;;;;:::i;:::-;145258:52;;145388:7;145376:8;:19;145372:316;;145496:1;145479:11;145491:1;145479:14;;;;;;;;:::i;:::-;;;;;;;;;;:18;145372:316;;;145563:13;145579:21;:8;145592:7;145579:12;:21::i;:::-;145563:37;;145640:28;145652:15;;145641:5;145640:11;;:28;;;;:::i;:::-;145623:11;145635:1;145623:14;;;;;;;;:::i;:::-;;;;;;;;;;:45;-1:-1:-1;145372:316:0;-1:-1:-1;;144650:3:0;;144605:1111;;2995:192;3081:7;3117:12;3109:6;;;;3101:29;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;3141:9:0;3153:5;3157:1;3153;:5;:::i;5039:345::-;5125:7;5227:12;5220:5;5212:28;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;5251:9:0;5263:5;5267:1;5263;:5;:::i;134864:417::-;134926:21;;;;134922:352;;135005:25;135033:15;135040:7;135033:6;:15::i;:::-;135005:43;;135068:9;135063:200;135087:12;:19;135083:23;;135063:200;;;135155:8;135164:1;135155:11;;;;;;;;:::i;:::-;;;;;;;;;;;;135133:16;;;;;;;:7;:16;;;;;;:19;;;;;;;;;;:33;135223:21;:24;;135150:1;;135223:24;;;;;;:::i;:::-;;;;;;;;;;;;;135185:32;;;;;:23;:32;;;;;;:35;;;;;;;;:62;135108:3;;135063:200;;134922:352;134864:417;:::o;14:196:1:-;82:20;;142:42;131:54;;121:65;;111:93;;200:1;197;190:12;215:186;274:6;327:2;315:9;306:7;302:23;298:32;295:52;;;343:1;340;333:12;295:52;366:29;385:9;366:29;:::i;406:632::-;577:2;629:21;;;699:13;;602:18;;;721:22;;;548:4;;577:2;800:15;;;;774:2;759:18;;;548:4;843:169;857:6;854:1;851:13;843:169;;;918:13;;906:26;;987:15;;;;952:12;;;;879:1;872:9;843:169;;;-1:-1:-1;1029:3:1;;406:632;-1:-1:-1;;;;;;406:632:1:o;1043:180::-;1102:6;1155:2;1143:9;1134:7;1130:23;1126:32;1123:52;;;1171:1;1168;1161:12;1123:52;-1:-1:-1;1194:23:1;;1043:180;-1:-1:-1;1043:180:1:o;1641:248::-;1709:6;1717;1770:2;1758:9;1749:7;1745:23;1741:32;1738:52;;;1786:1;1783;1776:12;1738:52;-1:-1:-1;;1809:23:1;;;1879:2;1864:18;;;1851:32;;-1:-1:-1;1641:248:1:o;2140:1011::-;2369:2;2421:21;;;2491:13;;2394:18;;;2513:22;;;2340:4;;2369:2;2554;;2572:18;;;;2613:15;;;2340:4;2656:469;2670:6;2667:1;2664:13;2656:469;;;2729:13;;2767:9;;2755:22;;2817:11;;;2811:18;2797:12;;;2790:40;2870:11;;;2864:18;2850:12;;;2843:40;2906:4;2950:11;;;2944:18;2930:12;;;2923:40;2986:4;3030:11;;;3024:18;3010:12;;;3003:40;3072:4;3063:14;;;;3100:15;;;;2692:1;2685:9;2656:469;;;-1:-1:-1;3142:3:1;;2140:1011;-1:-1:-1;;;;;;;2140:1011:1:o;3156:391::-;3242:6;3250;3258;3266;3319:3;3307:9;3298:7;3294:23;3290:33;3287:53;;;3336:1;3333;3326:12;3287:53;3359:29;3378:9;3359:29;:::i;:::-;3349:39;3435:2;3420:18;;3407:32;;-1:-1:-1;3486:2:1;3471:18;;3458:32;;3537:2;3522:18;3509:32;;-1:-1:-1;3156:391:1;-1:-1:-1;;;3156:391:1:o;3744:250::-;3829:1;3839:113;3853:6;3850:1;3847:13;3839:113;;;3929:11;;;3923:18;3910:11;;;3903:39;3875:2;3868:10;3839:113;;;-1:-1:-1;;3986:1:1;3968:16;;3961:27;3744:250::o;3999:455::-;4148:2;4137:9;4130:21;4111:4;4180:6;4174:13;4223:6;4218:2;4207:9;4203:18;4196:34;4239:79;4311:6;4306:2;4295:9;4291:18;4286:2;4278:6;4274:15;4239:79;:::i;:::-;4370:2;4358:15;4375:66;4354:88;4339:104;;;;4445:2;4335:113;;3999:455;-1:-1:-1;;3999:455:1:o;4459:316::-;4536:6;4544;4552;4605:2;4593:9;4584:7;4580:23;4576:32;4573:52;;;4621:1;4618;4611:12;4573:52;-1:-1:-1;;4644:23:1;;;4714:2;4699:18;;4686:32;;-1:-1:-1;4765:2:1;4750:18;;;4737:32;;4459:316;-1:-1:-1;4459:316:1:o;5033:254::-;5101:6;5109;5162:2;5150:9;5141:7;5137:23;5133:32;5130:52;;;5178:1;5175;5168:12;5130:52;5201:29;5220:9;5201:29;:::i;:::-;5191:39;5277:2;5262:18;;;;5249:32;;-1:-1:-1;;;5033:254:1:o;6084:118::-;6170:5;6163:13;6156:21;6149:5;6146:32;6136:60;;6192:1;6189;6182:12;6207:309;6272:6;6280;6333:2;6321:9;6312:7;6308:23;6304:32;6301:52;;;6349:1;6346;6339:12;6301:52;6385:9;6372:23;6362:33;;6445:2;6434:9;6430:18;6417:32;6458:28;6480:5;6458:28;:::i;:::-;6505:5;6495:15;;;6207:309;;;;;:::o;6521:260::-;6589:6;6597;6650:2;6638:9;6629:7;6625:23;6621:32;6618:52;;;6666:1;6663;6656:12;6618:52;6689:29;6708:9;6689:29;:::i;:::-;6679:39;;6737:38;6771:2;6760:9;6756:18;6737:38;:::i;:::-;6727:48;;6521:260;;;;;:::o;7560:184::-;7612:77;7609:1;7602:88;7709:4;7706:1;7699:15;7733:4;7730:1;7723:15;7749:184;7801:77;7798:1;7791:88;7898:4;7895:1;7888:15;7922:4;7919:1;7912:15;8288:184;8340:77;8337:1;8330:88;8437:4;8434:1;8427:15;8461:4;8458:1;8451:15;8477:168;8550:9;;;8581;;8598:15;;;8592:22;;8578:37;8568:71;;8619:18;;:::i;8650:274::-;8690:1;8716;8706:189;;8751:77;8748:1;8741:88;8852:4;8849:1;8842:15;8880:4;8877:1;8870:15;8706:189;-1:-1:-1;8909:9:1;;8650:274::o;11452:184::-;11522:6;11575:2;11563:9;11554:7;11550:23;11546:32;11543:52;;;11591:1;11588;11581:12;11543:52;-1:-1:-1;11614:16:1;;11452:184;-1:-1:-1;11452:184:1:o;11995:437::-;12074:1;12070:12;;;;12117;;;12138:61;;12192:4;12184:6;12180:17;12170:27;;12138:61;12245:2;12237:6;12234:14;12214:18;12211:38;12208:218;;12282:77;12279:1;12272:88;12383:4;12380:1;12373:15;12411:4;12408:1;12401:15;12437:188;12516:13;;12569:30;12558:42;;12548:53;;12538:81;;12615:1;12612;12605:12;12630:450;12717:6;12725;12733;12786:2;12774:9;12765:7;12761:23;12757:32;12754:52;;;12802:1;12799;12792:12;12754:52;12825:40;12855:9;12825:40;:::i;:::-;12815:50;;12884:49;12929:2;12918:9;12914:18;12884:49;:::i;:::-;12874:59;;12976:2;12965:9;12961:18;12955:25;13020:10;13013:5;13009:22;13002:5;12999:33;12989:61;;13046:1;13043;13036:12;12989:61;13069:5;13059:15;;;12630:450;;;;;:::o;14196:128::-;14263:9;;;14284:11;;;14281:37;;;14298:18;;:::i;14329:125::-;14394:9;;;14415:10;;;14412:36;;;14428:18;;:::i;15515:245::-;15582:6;15635:2;15623:9;15614:7;15610:23;15606:32;15603:52;;;15651:1;15648;15641:12;15603:52;15683:9;15677:16;15702:28;15724:5;15702:28;:::i;24884:287::-;25013:3;25051:6;25045:13;25067:66;25126:6;25121:3;25114:4;25106:6;25102:17;25067:66;:::i;:::-;25149:16;;;;;24884:287;-1:-1:-1;;24884:287:1:o
Swarm Source
ipfs://3f019bfa0dfa21e47e837705158f7cb00b04eca5bc59099971f9825dec0548dc
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$3,513.74
Net Worth in FRAX
3,386.505794
Token Allocations
WFRAX
100.00%
Multichain Portfolio | 35 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|---|---|---|---|---|
| FRAXTAL | 100.00% | $1.04 | 3,385.1102 | $3,513.74 |
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.