Source Code
Latest 25 from a total of 2,467 transactions
| Transaction Hash |
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
| Withdraw Locked | 414251792 | 30 days ago | IN | 0 ETH | 0.00015288 | ||||
| Withdraw Locked | 414251613 | 30 days ago | IN | 0 ETH | 0.00018969 | ||||
| Withdraw Locked | 400946672 | 69 days ago | IN | 0 ETH | 0.00001206 | ||||
| Get Reward | 369279334 | 160 days ago | IN | 0 ETH | 0.00000651 | ||||
| Get Reward | 366367749 | 169 days ago | IN | 0 ETH | 0.00000593 | ||||
| Withdraw Locked | 357566184 | 194 days ago | IN | 0 ETH | 0.00000773 | ||||
| Withdraw Locked | 357565946 | 194 days ago | IN | 0 ETH | 0.00000782 | ||||
| Withdraw Locked | 357565831 | 194 days ago | IN | 0 ETH | 0.00000942 | ||||
| Get Reward | 347591000 | 223 days ago | IN | 0 ETH | 0.0000061 | ||||
| Withdraw Locked | 338623566 | 249 days ago | IN | 0 ETH | 0.0000075 | ||||
| Get Reward | 338621174 | 249 days ago | IN | 0 ETH | 0.00000382 | ||||
| Get Reward | 337978921 | 251 days ago | IN | 0 ETH | 0.00000263 | ||||
| Withdraw Locked | 337350572 | 253 days ago | IN | 0 ETH | 0.00000749 | ||||
| Get Reward | 337350491 | 253 days ago | IN | 0 ETH | 0.00000269 | ||||
| Get Reward | 337229406 | 253 days ago | IN | 0 ETH | 0.00000606 | ||||
| Withdraw Locked | 334605536 | 261 days ago | IN | 0 ETH | 0.00001006 | ||||
| Withdraw Locked | 334605458 | 261 days ago | IN | 0 ETH | 0.00001034 | ||||
| Get Reward | 328638196 | 278 days ago | IN | 0 ETH | 0.00000638 | ||||
| Get Reward | 325787752 | 286 days ago | IN | 0 ETH | 0.00000263 | ||||
| Withdraw Locked | 324307146 | 291 days ago | IN | 0 ETH | 0.00000956 | ||||
| Get Reward | 324306775 | 291 days ago | IN | 0 ETH | 0.00000886 | ||||
| Get Reward | 319851484 | 304 days ago | IN | 0 ETH | 0.00000306 | ||||
| Get Reward | 318858092 | 306 days ago | IN | 0 ETH | 0.00000262 | ||||
| Get Reward | 318795837 | 307 days ago | IN | 0 ETH | 0.00000293 | ||||
| Get Reward | 318746615 | 307 days ago | IN | 0 ETH | 0.00000608 |
Cross-Chain Transactions
Loading...
Loading
Contract Name:
FraxCCFarmV4_cvxLP
Compiler Version
v0.8.23+commit.f704f362
Contract Source Code (Solidity)
/**
*Submitted for verification at Arbiscan.io on 2023-12-03
*/
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.8.0;
// Sources flattened with hardhat v2.17.3 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/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/Misc_AMOs/convex/IConvexCvxLPRewardPoolCombo.sol
// Original license: SPDX_License_Identifier: GPL-2.0-or-later
interface IConvexCvxLPRewardPoolCombo {
struct EarnedData {
address token;
uint256 amount;
}
function addExtraReward ( address _token ) external;
function allowance ( address owner, address spender ) external view returns ( uint256 );
function approve ( address spender, uint256 amount ) external returns ( bool );
function balanceOf ( address account ) external view returns ( uint256 );
function claimable_reward ( address, address ) external view returns ( uint256 );
function convexBooster ( ) external view returns ( address );
function convexPoolId ( ) external view returns ( uint256 );
function convexStaker ( ) external view returns ( address );
function crv ( ) external view returns ( address );
function curveGauge ( ) external view returns ( address );
function decimals ( ) external pure returns ( uint8 );
function decreaseAllowance ( address spender, uint256 subtractedValue ) external returns ( bool );
function earned ( address _account ) external returns ( EarnedData[] memory claimable );
function emergencyWithdraw ( uint256 _amount ) external returns ( bool );
function getReward ( address _account, address _forwardTo ) external;
function getReward ( address _account ) external;
function increaseAllowance ( address spender, uint256 addedValue ) external returns ( bool );
function initialize ( address _crv, address _curveGauge, address _convexStaker, address _convexBooster, address _lptoken, uint256 _poolId ) external;
function invalidateReward ( address _token ) external;
function maxRewards ( ) external view returns ( uint256 );
function name ( ) external view returns ( string memory );
function rewardHook ( ) external view returns ( address );
function rewardLength ( ) external view returns ( uint256 );
function rewardMap ( address ) external view returns ( uint256 );
function rewardRedirect ( address ) external view returns ( address );
function reward_integral_for ( address, address ) external view returns ( uint256 );
function rewards ( uint256 ) external view returns ( address reward_token, uint256 reward_integral, uint256 reward_remaining );
function setRewardHook ( address _hook ) external;
function setRewardRedirect ( address _to ) external;
function stakeFor ( address _for, uint256 _amount ) external returns ( bool );
function symbol ( ) external view returns ( string memory );
function totalSupply ( ) external view returns ( uint256 );
function transfer ( address recipient, uint256 amount ) external returns ( bool );
function transferFrom ( address sender, address recipient, uint256 amount ) external returns ( bool );
function user_checkpoint ( address _account ) external returns ( bool );
function withdraw ( uint256 _amount, bool _claim ) external returns ( bool );
function withdrawAll ( bool claim ) external;
}
// File contracts/Misc_AMOs/curve/I2poolTokenNoLending.sol
// Original license: SPDX_License_Identifier: GPL-2.0-or-later
interface I2poolTokenNoLending {
function initialize ( string memory _name, string memory _symbol, address[4] memory _coins, uint256[4] memory _rate_multipliers, uint256 _A, uint256 _fee ) external;
function decimals ( ) external view returns ( uint8 );
function transfer ( address _to, uint256 _value ) external returns ( bool );
function transferFrom ( address _from, address _to, uint256 _value ) external returns ( bool );
function approve ( address _spender, uint256 _value ) external returns ( bool );
function permit ( address _owner, address _spender, uint256 _value, uint256 _deadline, uint8 _v, bytes32 _r, bytes32 _s ) external returns ( bool );
function last_price ( ) external view returns ( uint256 );
function ema_price ( ) external view returns ( uint256 );
function get_balances ( ) external view returns ( uint256[2] memory );
function admin_fee ( ) external view returns ( uint256 );
function A ( ) external view returns ( uint256 );
function A_precise ( ) external view returns ( uint256 );
function get_p ( ) external view returns ( uint256 );
function price_oracle ( ) external view returns ( uint256 );
function get_virtual_price ( ) external view returns ( uint256 );
function calc_token_amount ( uint256[2] memory _amounts, bool _is_deposit ) external view returns ( uint256 );
function add_liquidity ( uint256[2] memory _amounts, uint256 _min_mint_amount ) external returns ( uint256 );
function add_liquidity ( uint256[2] memory _amounts, uint256 _min_mint_amount, address _receiver ) external returns ( uint256 );
function get_dy ( int128 i, int128 j, uint256 dx ) external view returns ( uint256 );
function get_dx ( int128 i, int128 j, uint256 dy ) external view returns ( uint256 );
function exchange ( int128 i, int128 j, uint256 _dx, uint256 _min_dy ) external returns ( uint256 );
function exchange ( int128 i, int128 j, uint256 _dx, uint256 _min_dy, address _receiver ) external returns ( uint256 );
function remove_liquidity ( uint256 _burn_amount, uint256[2] memory _min_amounts ) external returns ( uint256[2] memory );
function remove_liquidity ( uint256 _burn_amount, uint256[2] memory _min_amounts, address _receiver ) external returns ( uint256[2] memory );
function remove_liquidity_imbalance ( uint256[2] memory _amounts, uint256 _max_burn_amount ) external returns ( uint256 );
function remove_liquidity_imbalance ( uint256[2] memory _amounts, uint256 _max_burn_amount, address _receiver ) external returns ( uint256 );
function calc_withdraw_one_coin ( uint256 _burn_amount, int128 i ) external view returns ( uint256 );
function remove_liquidity_one_coin ( uint256 _burn_amount, int128 i, uint256 _min_received ) external returns ( uint256 );
function remove_liquidity_one_coin ( uint256 _burn_amount, int128 i, uint256 _min_received, address _receiver ) external returns ( uint256 );
function ramp_A ( uint256 _future_A, uint256 _future_time ) external;
function stop_ramp_A ( ) external;
function set_ma_exp_time ( uint256 _ma_exp_time ) external;
function admin_balances ( uint256 i ) external view returns ( uint256 );
function commit_new_fee ( uint256 _new_fee ) external;
function apply_new_fee ( ) external;
function withdraw_admin_fees ( ) external;
function version ( ) external pure returns ( string memory );
function factory ( ) external view returns ( address );
function coins ( uint256 arg0 ) external view returns ( address );
function balances ( uint256 arg0 ) external view returns ( uint256 );
function fee ( ) external view returns ( uint256 );
function future_fee ( ) external view returns ( uint256 );
function admin_action_deadline ( ) external view returns ( uint256 );
function initial_A ( ) external view returns ( uint256 );
function future_A ( ) external view returns ( uint256 );
function initial_A_time ( ) external view returns ( uint256 );
function future_A_time ( ) external view returns ( uint256 );
function name ( ) external view returns ( string memory );
function symbol ( ) external view returns ( string memory );
function balanceOf ( address arg0 ) external view returns ( uint256 );
function allowance ( address arg0, address arg1 ) external view returns ( uint256 );
function totalSupply ( ) external view returns ( uint256 );
function DOMAIN_SEPARATOR ( ) external view returns ( bytes32 );
function nonces ( address arg0 ) external view returns ( uint256 );
function ma_exp_time ( ) external view returns ( uint256 );
function ma_last_time ( ) external view returns ( uint256 );
}
// File contracts/Misc_AMOs/curve/ICurveChildLiquidityGauge.sol
// Original license: SPDX_License_Identifier: GPL-2.0-or-later
interface ICurveChildLiquidityGauge {
struct Reward {
address distributor;
uint256 period_finish;
uint256 rate;
uint256 last_update;
uint256 integral;
}
function deposit ( uint256 _value ) external;
function deposit ( uint256 _value, address _user ) external;
function deposit ( uint256 _value, address _user, bool _claim_rewards ) external;
function withdraw ( uint256 _value ) external;
function withdraw ( uint256 _value, address _user ) external;
function withdraw ( uint256 _value, address _user, bool _claim_rewards ) external;
function transferFrom ( address _from, address _to, uint256 _value ) external returns ( bool );
function approve ( address _spender, uint256 _value ) external returns ( bool );
function permit ( address _owner, address _spender, uint256 _value, uint256 _deadline, uint8 _v, bytes32 _r, bytes32 _s ) external returns ( bool );
function transfer ( address _to, uint256 _value ) external returns ( bool );
function increaseAllowance ( address _spender, uint256 _added_value ) external returns ( bool );
function decreaseAllowance ( address _spender, uint256 _subtracted_value ) external returns ( bool );
function user_checkpoint ( address addr ) external returns ( bool );
function claimable_tokens ( address addr ) external returns ( uint256 );
function claimed_reward ( address _addr, address _token ) external view returns ( uint256 );
function claimable_reward ( address _user, address _reward_token ) external view returns ( uint256 );
function set_rewards_receiver ( address _receiver ) external;
function claim_rewards ( ) external;
function claim_rewards ( address _addr ) external;
function claim_rewards ( address _addr, address _receiver ) external;
function add_reward ( address _reward_token, address _distributor ) external;
function set_reward_distributor ( address _reward_token, address _distributor ) external;
function deposit_reward_token ( address _reward_token, uint256 _amount ) external;
function set_manager ( address _manager ) external;
function update_voting_escrow ( ) external;
function set_killed ( bool _is_killed ) external;
function decimals ( ) external view returns ( uint256 );
function integrate_checkpoint ( ) external view returns ( uint256 );
function version ( ) external view returns ( string memory );
function factory ( ) external view returns ( address );
function initialize ( address _lp_token, address _manager ) external;
function DOMAIN_SEPARATOR ( ) external view returns ( bytes32 );
function nonces ( address arg0 ) external view returns ( uint256 );
function name ( ) external view returns ( string memory );
function symbol ( ) external view returns ( string memory );
function allowance ( address arg0, address arg1 ) external view returns ( uint256 );
function balanceOf ( address arg0 ) external view returns ( uint256 );
function totalSupply ( ) external view returns ( uint256 );
function lp_token ( ) external view returns ( address );
function manager ( ) external view returns ( address );
function voting_escrow ( ) external view returns ( address );
function working_balances ( address arg0 ) external view returns ( uint256 );
function working_supply ( ) external view returns ( uint256 );
function period ( ) external view returns ( uint256 );
function period_timestamp ( uint256 arg0 ) external view returns ( uint256 );
function integrate_checkpoint_of ( address arg0 ) external view returns ( uint256 );
function integrate_fraction ( address arg0 ) external view returns ( uint256 );
function integrate_inv_supply ( uint256 arg0 ) external view returns ( uint256 );
function integrate_inv_supply_of ( address arg0 ) external view returns ( uint256 );
function reward_count ( ) external view returns ( uint256 );
function reward_tokens ( uint256 arg0 ) external view returns ( address );
function reward_data ( address arg0 ) external view returns ( Reward memory );
function rewards_receiver ( address arg0 ) external view returns ( address );
function reward_integral_for ( address arg0, address arg1 ) external view returns ( uint256 );
function is_killed ( ) external view returns ( bool );
function inflation_rate ( uint256 arg0 ) external view returns ( uint256 );
}
// File contracts/Oracle/AggregatorV3Interface.sol
// Original license: SPDX_License_Identifier: MIT
interface AggregatorV3Interface {
function decimals() external view returns (uint8);
function description() external view returns (string memory);
function version() external view returns (uint256);
// getRoundData and latestRoundData should both raise "No data present"
// if they do not have data to report, instead of returning unset values
// which could be misinterpreted as actual reported values.
function getRoundData(uint80 _roundId)
external
view
returns (
uint80 roundId,
int256 answer,
uint256 startedAt,
uint256 updatedAt,
uint80 answeredInRound
);
function latestRoundData()
external
view
returns (
uint80 roundId,
int256 answer,
uint256 startedAt,
uint256 updatedAt,
uint80 answeredInRound
);
}
// 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
// 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
// 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
/// @notice If reward collection on withdrawal is disabled
bool public collectRewardsOnWithdrawalPaused;
/// @notice If this contract has been initialized
bool public isInitialized;
/// @notice Version
string public version = "0.0.8";
/* ========== 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 == false, "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 = 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
}
// 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;
// }
// 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) {
for (uint256 i = 0; i < lockedStakes[staker_address].length; i++) {
if (kek_id == lockedStakes[staker_address][i].kek_id){
locked_stake = lockedStakes[staker_address][i];
arr_idx = i;
break;
}
}
require(locked_stake.kek_id == kek_id, "Stake not found");
}
/// @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 {
// 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
_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
/// @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 updateRewardAndBalance(msg.sender, true) public {
// Make sure staking isn't paused
require(!stakingPaused, "Staking paused");
// 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
/// @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 updateRewardAndBalance(msg.sender, true) public {
// Make sure staking isn't paused
require(!stakingPaused, "Staking paused");
// 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(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 Whether you want to claim rewards during withdrawal
/// @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) nonReentrant public {
require(withdrawalsPaused == false, "Withdrawals paused");
_withdrawLocked(msg.sender, msg.sender, kek_id, claim_rewards);
}
/// @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 Whether you want to claim rewards during withdrawal
function _withdrawLocked(address staker_address, address destination_address, bytes32 kek_id, bool claim_rewards) internal {
// Collect rewards first and then update the balances
// collectRewardsOnWithdrawalPaused 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. User can also specify it in withdrawLocked
if (claim_rewards || !collectRewardsOnWithdrawalPaused) _getReward(staker_address, destination_address);
else {
// Sync the rewards at least
_updateRewardAndBalance(staker_address, true, false);
}
(LockedStake memory thisStake, uint256 theArrayIndex) = _getStake(staker_address, kek_id);
require(thisStake.kek_id == kek_id, "Stake not found");
require(block.timestamp >= thisStake.ending_timestamp || stakesUnlocked == true || valid_migrators[msg.sender] == true, "Stake is still locked!");
uint256 liquidity = thisStake.liquidity;
if (liquidity > 0) {
// Update liquidities
_total_liquidity_locked = _total_liquidity_locked.sub(liquidity);
_locked_liquidity[staker_address] = _locked_liquidity[staker_address].sub(liquidity);
// Remove the stake from the array
delete lockedStakes[staker_address][theArrayIndex];
// Need to call to update the combined weights
_updateRewardAndBalance(staker_address, 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) {
_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 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 Toggle reward collection upon withdrawal
function toggleCollectRewardsOnWithdrawal() external onlyByOwnGov {
collectRewardsOnWithdrawalPaused = !collectRewardsOnWithdrawalPaused;
}
/// @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":[],"name":"collectRewardsOnWithdrawalPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"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":"getLatestETHPriceE8","outputs":[{"internalType":"int256","name":"","type":"int256"}],"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":"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":"address","name":"_eth_usd_oracle_address","type":"address"}],"name":"setETHUSDOracle","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 IConvexCvxLPRewardPoolCombo","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":"toggleCollectRewardsOnWithdrawal","outputs":[],"stateMutability":"nonpayable","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","type":"bool"}],"name":"withdrawLocked","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"withdrawalsPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}]Contract Creation Code
600580546001600160a01b03191673639fe6ab55c921f74e7fac1ee960c0b6293ba6121781556729a2241af62c0000600d556305a39a80600e556001600f55673782dace9d900000601055671bc16d674ec8000060115562093a8060165560c06040526080908152640605c605c760db1b60a05260279062000082908262000550565b5060408051808201909152601281527104672617843434661726d56345f6376784c560741b6020820152602890620000bb908262000550565b50348015620000c957600080fd5b506040516200611e3803806200611e833981016040819052620000ec9162000639565b858585858585856001600160a01b0381166200014f5760405162461bcd60e51b815260206004820152601960248201527f4f776e657220616464726573732063616e6e6f7420626520300000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b03831690811782556040805192835260208301919091527fb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159c910160405180910390a1506001600255600880546001600160a01b0319166001600160a01b0385161790558451620001dc90600490602088019062000428565b5060005b8551811015620003485780601560008884815181106200020457620002046200076b565b60200260200101516001600160a01b03166001600160a01b03168152602001908152602001600020819055506001601460008884815181106200024b576200024b6200076b565b6020908102919091018101516001600160a01b031682528101919091526040016000908120805460ff1916921515929092179091556019805460018181019092557f944998273e477b495144fb8794c914197f3ccb46be2900f4698fd0ef743c969501829055601780548083019091557fc624b66cc0138b8fabc209247f72d758e1cf3343756d543badbf24212bed8c1501829055601880548083019091557fb13d2d76d1f4b7be834882e410b3e3a8afaf69f83600ae24db354391d2378d2e018290556013805480830182559083527f66de8ffda797e3de9c05e8fc57b3bf0ec28a930d40b0d285d93c06501cf6a090019190915501620001e0565b50600680546001600160a01b038087166001600160a01b0319928316179092556009805485841690831617905560078054928416929091169190911790556026805461ffff1916905542600c819055601654620003a69190620003bc565b600b5550620007a39a5050505050505050505050565b600080620003cb838562000781565b9050838110156200041f5760405162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015260640162000146565b90505b92915050565b82805482825590600052602060002090810192821562000480579160200282015b828111156200048057825182546001600160a01b0319166001600160a01b0390911617825560209092019160019091019062000449565b506200048e92915062000492565b5090565b5b808211156200048e576000815560010162000493565b634e487b7160e01b600052604160045260246000fd5b600181811c90821680620004d457607f821691505b602082108103620004f557634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200054b576000816000526020600020601f850160051c81016020861015620005265750805b601f850160051c820191505b81811015620005475782815560010162000532565b5050505b505050565b81516001600160401b038111156200056c576200056c620004a9565b62000584816200057d8454620004bf565b84620004fb565b602080601f831160018114620005bc5760008415620005a35750858301515b600019600386901b1c1916600185901b17855562000547565b600085815260208120601f198616915b82811015620005ed57888601518255948401946001909101908401620005cc565b50858210156200060c5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b80516001600160a01b03811681146200063457600080fd5b919050565b60008060008060008060c087890312156200065357600080fd5b6200065e876200061c565b602088810151919750906001600160401b03808211156200067e57600080fd5b818a0191508a601f8301126200069357600080fd5b815181811115620006a857620006a8620004a9565b8060051b604051601f19603f83011681018181108582111715620006d057620006d0620004a9565b60405291825284820192508381018501918d831115620006ef57600080fd5b938501935b82851015620007185762000708856200061c565b84529385019392850192620006f4565b809a505050505050506200072f604088016200061c565b93506200073f606088016200061c565b92506200074f608088016200061c565b91506200075f60a088016200061c565b90509295509295509295565b634e487b7160e01b600052603260045260246000fd5b808201808211156200042257634e487b7160e01b600052601160045260246000fd5b61596b80620007b36000396000f3fe608060405234801561001057600080fd5b50600436106105495760003560e01c80637b31c19a116102bc578063c8f33c9111610186578063e9f2838e116100e3578063f288baf611610097578063f2caeb1e1161007c578063f2caeb1e14610bc4578063fce6fd1314610bd7578063fff6cae914610be457600080fd5b8063f288baf614610bb2578063f2a8d34914610bbb57600080fd5b8063ebe2b12b116100c8578063ebe2b12b14610b73578063ee89e02f14610b7c578063f12f144714610b9f57600080fd5b8063e9f2838e14610b4d578063eb3c209e14610b6057600080fd5b8063d42fc9b41161013a578063dcc3e06e1161011f578063dcc3e06e14610b1d578063e01f62bf14610b3d578063e1ba95d214610b4557600080fd5b8063d42fc9b414610ad5578063d9f96e8d14610ae857600080fd5b8063cdc82e801161016b578063cdc82e8014610ab1578063d239f00314610aba578063d2fbdc0d14610ac257600080fd5b8063c8f33c9114610aa0578063cd3daf9d14610aa957600080fd5b80639b8c15a811610234578063b85efd06116101e8578063bbb781cc116101cd578063bbb781cc14610a70578063bdacb30314610a85578063bdb123e314610a9857600080fd5b8063b85efd0614610a54578063b94c4dcb14610a6757600080fd5b8063a2217bc511610219578063a2217bc514610a26578063a65fd70a14610a2e578063af00f4e214610a4157600080fd5b80639b8c15a8146109e55780639c5303eb14610a1357600080fd5b80638bad86a71161028b578063903bd2af11610270578063903bd2af146109ad57806392eefe9b146109c05780639637927f146109d357600080fd5b80638bad86a71461095f5780638da5cb5b1461098d57600080fd5b80637b31c19a1461091e5780637bb7bed114610926578063818a2ba6146109395780638980f11f1461094c57600080fd5b80633b8105b31161041857806364f2c0601161037557806372f702f311610329578063774d4ae71161030e578063774d4ae7146108c85780637970833e146108db57806379ba50971461091657600080fd5b806372f702f314610895578063741d3c18146108b557600080fd5b80636ce46bc31161035a5780636ce46bc3146108705780636cea0b0d146108835780636e27cef91461088c57600080fd5b806364f2c06014610848578063693392451461085057600080fd5b80634fd2b536116103cc57806353a47bb7116103b157806353a47bb71461081857806354fd4d50146108385780635bfd92581461084057600080fd5b80634fd2b5361461079e57806352732bc8146107b157600080fd5b806341edbdf0116103fd57806341edbdf0146107495780634b24ea471461075e5780634bc66f321461077e57600080fd5b80633b8105b3146107395780633d18b9121461074157600080fd5b80631b3e870a116104c65780632c0c2a0a1161047a57806336f89af21161045f57806336f89af2146106e3578063386a952514610719578063392e53cd1461072257600080fd5b80632c0c2a0a146106bc578063323331ca146106cf57600080fd5b80631e090f01116104ab5780631e090f011461066357806328ef934e146106835780632bd59b631461069657600080fd5b80631b3e870a146106485780631c1f78eb1461065b57600080fd5b8063169d27ef1161051d57806317b18c891161050257806317b18c891461060d57806318c971ae1461062057806319ff52fd1461062857600080fd5b8063169d27ef146105c0578063174ed0ca146105c857600080fd5b80628cc2621461054e578063046e7d3f146105775780630d7bac4f1461058c5780631627540c146105ad575b600080fd5b61056161055c36600461548c565b610bec565b60405161056e91906154a9565b60405180910390f35b61058a61058536600461548c565b610da4565b005b61059f61059a3660046154ed565b610e93565b60405190815260200161056e565b61058a6105bb36600461548c565b610ebf565b61058a610fdf565b6008546105e89073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161056e565b61058a61061b366004615506565b61117f565b61058a611204565b6003546105e89073ffffffffffffffffffffffffffffffffffffffff1681565b61058a61065636600461548c565b6112e5565b610561611468565b61067661067136600461548c565b61151a565b60405161056e9190615528565b61058a610691366004615596565b6115ce565b6026546106ac9065010000000000900460ff1681565b604051901515815260200161056e565b61059f6106ca36600461548c565b611707565b6026546106ac906301000000900460ff1681565b61059f6106f136600461548c565b73ffffffffffffffffffffffffffffffffffffffff1660009081526021602052604090205490565b61059f60165481565b6026546106ac906601000000000000900460ff1681565b61058a61183a565b61056161191a565b610751611a13565b60405161056e91906155f5565b600a546105e89073ffffffffffffffffffffffffffffffffffffffff1681565b6009546105e89073ffffffffffffffffffffffffffffffffffffffff1681565b61059f6107ac36600461548c565b611aa1565b61058a6107bf36600461548c565b33600090815260256020908152604080832073ffffffffffffffffffffffffffffffffffffffff9490941683529290522080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055565b6001546105e89073ffffffffffffffffffffffffffffffffffffffff1681565b610751611abe565b61059f611acb565b601f5461059f565b61059f61085e36600461548c565b60156020526000908152604090205481565b61058a61087e366004615646565b611d26565b61059f601c5481565b61059f600f5481565b6006546105e89073ffffffffffffffffffffffffffffffffffffffff1681565b61058a6108c336600461548c565b611f87565b61059f6108d6366004615672565b6120ee565b6108ee6108e9366004615672565b6122fa565b604080519586526020860194909452928401919091526060830152608082015260a00161056e565b61058a612348565b61058a612493565b6105e86109343660046154ed565b612572565b61059f6109473660046154ed565b6125a9565b61058a61095a366004615672565b6125ca565b61097261096d36600461548c565b6127ee565b6040805193845260208401929092529082015260600161056e565b6000546105e89073ffffffffffffffffffffffffffffffffffffffff1681565b61058a6109bb3660046156ac565b612a1a565b61058a6109ce36600461548c565b612b08565b6026546106ac90610100900460ff1681565b6106ac6109f33660046156dc565b602560209081526000928352604080842090915290825290205460ff1681565b61058a610a2136600461548c565b612bf2565b61058a612ce4565b61059f610a3c3660046154ed565b612db9565b61058a610a4f366004615506565b612dc9565b61058a610a62366004615506565b612faf565b61059f600e5481565b6026546106ac90640100000000900460ff1681565b61058a610a9336600461548c565b613212565b61059f6132fc565b61059f600c5481565b610561613441565b61059f600d5481565b61058a61359f565b61058a610ad0366004615506565b61367d565b61059f610ae336600461548c565b613a5a565b61059f610af636600461548c565b73ffffffffffffffffffffffffffffffffffffffff16600090815260208052604090205490565b6007546105e89073ffffffffffffffffffffffffffffffffffffffff1681565b601e5461059f565b61058a613a99565b6026546106ac9062010000900460ff1681565b61058a610b6e366004615672565b613b76565b61059f600b5481565b6106ac610b8a36600461548c565b60246020526000908152604090205460ff1681565b61058a610bad36600461548c565b613cad565b61059f60115481565b61059f60105481565b61059f610bd23660046154ed565b613d98565b6026546106ac9060ff1681565b61058a613da8565b60045460609067ffffffffffffffff811115610c0a57610c0a61570a565b604051908082528060200260200182016040528015610c33578160200160208202803683370190505b5073ffffffffffffffffffffffffffffffffffffffff831660009081526021602052604081205491925003610c9c5760005b600454811015610c96576000828281518110610c8357610c83615739565b6020908102919091010152600101610c65565b50919050565b6000610ca6613441565b905060005b600454811015610d9c5773ffffffffffffffffffffffffffffffffffffffff84166000818152601b60209081526040808320858452825280832054938352601a82528083208584529091529020548351610d779291610d7191670de0b6b3a764000091610d6b91610d3f9190899089908110610d2957610d29615739565b6020026020010151613e3e90919063ffffffff16565b73ffffffffffffffffffffffffffffffffffffffff8a1660009081526021602052604090205490613e87565b90613f3f565b90613f81565b838281518110610d8957610d89615739565b6020908102919091010152600101610cab565b50505b919050565b60005473ffffffffffffffffffffffffffffffffffffffff16331480610de1575060095473ffffffffffffffffffffffffffffffffffffffff1633145b610e4c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b000000000000000000000060448201526064015b60405180910390fd5b600380547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b600d54600e54600091610eb991610eaa8286615797565b610eb491906157ae565b613ffa565b92915050565b60005473ffffffffffffffffffffffffffffffffffffffff163314610f66576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602f60248201527f4f6e6c792074686520636f6e7472616374206f776e6572206d6179207065726660448201527f6f726d207468697320616374696f6e00000000000000000000000000000000006064820152608401610e43565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040519081527f906a1c6bd7e3091ea86693dd029a831c19049ce77f1dce2ce0bab1cacbabce229060200160405180910390a150565b60005473ffffffffffffffffffffffffffffffffffffffff1633148061101c575060095473ffffffffffffffffffffffffffffffffffffffff1633145b8061103e5750600a5473ffffffffffffffffffffffffffffffffffffffff1633145b6110a4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4e6f74206f776e2c20746c6b2c206f72206374726c72000000000000000000006044820152606401610e43565b6026546601000000000000900460ff161561111b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f416c726561647920696e697469616c697a6564000000000000000000000000006044820152606401610e43565b602680547fffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffff166601000000000000179055611154613da8565b6040517fb5cfe3ccd03847076864f081609024cbc2eb98c38da4d8b2cebe9479a9a1ef3790600090a1565b60028054036111ea576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610e43565b600280556111fb3380848442614010565b50506001600255565b60005473ffffffffffffffffffffffffffffffffffffffff16331480611241575060095473ffffffffffffffffffffffffffffffffffffffff1633145b6112a7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b00000000000000000000006044820152606401610e43565b602680547fffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffffff8116650100000000009182900460ff1615909102179055565b60005473ffffffffffffffffffffffffffffffffffffffff16331480611322575060095473ffffffffffffffffffffffffffffffffffffffff1633145b611388576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b00000000000000000000006044820152606401610e43565b73ffffffffffffffffffffffffffffffffffffffff811660009081526024602052604090205460ff16151560011461141c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f41646472657373206e6f6e6578697374656e74000000000000000000000000006044820152606401610e43565b73ffffffffffffffffffffffffffffffffffffffff16600090815260246020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055565b60045460609067ffffffffffffffff8111156114865761148661570a565b6040519080825280602002602001820160405280156114af578160200160208202803683370190505b50905060005b600454811015611516576114f1601654601383815481106114d8576114d8615739565b9060005260206000200154613e8790919063ffffffff16565b82828151811061150357611503615739565b60209081029190910101526001016114b5565b5090565b73ffffffffffffffffffffffffffffffffffffffff81166000908152602360209081526040808320805482518185028101850190935280835260609492939192909184015b828210156115c357838290600052602060002090600502016040518060a0016040529081600082015481526020016001820154815260200160028201548152602001600382015481526020016004820154815250508152602001906001019061155f565b505050509050919050565b60265460ff16151560011461163f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f4e6f7420696e206d6967726174696f6e000000000000000000000000000000006044820152606401610e43565b73ffffffffffffffffffffffffffffffffffffffff8416600090815260256020908152604080832033845290915290205460ff16801561168e57503360009081526024602052604090205460ff165b6116f4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f4d69672e20696e76616c6964206f7220756e617070726f7665640000000000006044820152606401610e43565b6117018433858585614010565b50505050565b60035460009073ffffffffffffffffffffffffffffffffffffffff161561183257600061173383611aa1565b90508015611829576003546040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85811660048301526000926117eb928592610d6b92670de0b6b3a7640000929116906370a0823190602401602060405180830381865afa1580156117c1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117e591906157e9565b90613e87565b90506000611810670de0b6b3a7640000610d6b60115485613e8790919063ffffffff16565b905060115481111561182157506011545b949350505050565b50600092915050565b506000919050565b60005473ffffffffffffffffffffffffffffffffffffffff16331480611877575060095473ffffffffffffffffffffffffffffffffffffffff1633145b6118dd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b00000000000000000000006044820152606401610e43565b602680547fffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffff81166401000000009182900460ff1615909102179055565b60606002805403611987576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610e43565b600280556026546301000000900460ff16156119ff576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f5265776172647320636f6c6c656374696f6e20706175736564000000000000006044820152606401610e43565b611a093333614446565b9050600160025590565b60288054611a2090615802565b80601f0160208091040260200160405190810160405280929190818152602001828054611a4c90615802565b8015611a995780601f10611a6e57610100808354040283529160200191611a99565b820191906000526020600020905b815481529060010190602001808311611a7c57829003601f168201915b505050505081565b6000610eb9670de0b6b3a7640000610d6b6010546117e586613a5a565b60278054611a2090615802565b6000806000600660009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663280718e26040518163ffffffff1660e01b8152600401602060405180830381865afa158015611b3d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b61919061584f565b905060008173ffffffffffffffffffffffffffffffffffffffff166382c630666040518163ffffffff1660e01b8152600401602060405180830381865afa158015611bb0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bd4919061584f565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8216600482015290915060009073178412e79c25968a32e89b11f63b33f733770c2a906370a0823190602401602060405180830381865afa158015611c58573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c7c91906157e9565b905060008273ffffffffffffffffffffffffffffffffffffffff166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611ccb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cef91906157e9565b611cf76132fc565b611d019084615797565b611d0b91906157ae565b9050611d1c816402540be400615797565b9695505050505050565b60005473ffffffffffffffffffffffffffffffffffffffff16331480611d63575060095473ffffffffffffffffffffffffffffffffffffffff1633145b611dc9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b00000000000000000000006044820152606401610e43565b670de0b6b3a7640000831015611e60576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f4d756c74206d757374206265203e3d204d554c5449504c4945525f505245434960448201527f53494f4e000000000000000000000000000000000000000000000000000000006064820152608401610e43565b60008111611eca576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f766546585320706374206d6178206d757374206265203e3d20300000000000006044820152606401610e43565b600d839055601182905560108190556040518281527fc9d56ccdd6b954d8d74700db074cc667054f8e33c1b8d23e97021d4c588a87619060200160405180910390a17fa1676084a9eea08c6f205b60799323b364a1bd8e10aba89f0fbd94cfbf68b5dd600d54604051611f3f91815260200190565b60405180910390a17f58c7ececaeb4704a0039e0d22c1b618367f7a7b9a4e191ab9baed34898f63f2e601054604051611f7a91815260200190565b60405180910390a1505050565b60005473ffffffffffffffffffffffffffffffffffffffff16331480611fc4575060095473ffffffffffffffffffffffffffffffffffffffff1633145b61202a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b00000000000000000000006044820152606401610e43565b73ffffffffffffffffffffffffffffffffffffffff81166120a7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f5a65726f206164647265737320646574656374656400000000000000000000006044820152606401610e43565b600580547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b73ffffffffffffffffffffffffffffffffffffffff8216600090815260236020526040812080548291908490811061212857612128615739565b600091825260208083206040805160a081018252600590940290910180548452600181015484840181905260028201548584015260038201546060860152600490910154608085015273ffffffffffffffffffffffffffffffffffffffff89168552601d90925283205491935011156121a6575060208101516121ce565b5073ffffffffffffffffffffffffffffffffffffffff84166000908152601d60205260409020545b4282606001511161228e57606082015173ffffffffffffffffffffffffffffffffffffffff86166000908152601d6020526040902054101561228557600081836060015161221c919061586c565b90506000836060015142612230919061586c565b9050600061224261059a6002856157ae565b905060006122508382615797565b61225a8584615797565b612264919061587f565b9050612270838561587f565b61227a90826157ae565b9650505050506122de565b600092506122de565b6000808284606001516122a1919061586c565b905060004285606001516122b5919061586c565b905060026122c3828461587f565b6122cd91906157ae565b925050506122da81610e93565b9350505b81608001518311156122f257816080015192505b505092915050565b6023602052816000526040600020818154811061231657600080fd5b600091825260209091206005909102018054600182015460028301546003840154600490940154929550909350919085565b60015473ffffffffffffffffffffffffffffffffffffffff1633146123ef576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603560248201527f596f75206d757374206265206e6f6d696e61746564206265666f726520796f7560448201527f2063616e20616363657074206f776e65727368697000000000000000000000006064820152608401610e43565b6000546001546040805173ffffffffffffffffffffffffffffffffffffffff93841681529290911660208301527fb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159c910160405180910390a160018054600080547fffffffffffffffffffffffff000000000000000000000000000000000000000090811673ffffffffffffffffffffffffffffffffffffffff841617909155169055565b60005473ffffffffffffffffffffffffffffffffffffffff163314806124d0575060095473ffffffffffffffffffffffffffffffffffffffff1633145b612536576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b00000000000000000000006044820152606401610e43565b602680547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffff811663010000009182900460ff1615909102179055565b6004818154811061258257600080fd5b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff16905081565b601881815481106125b957600080fd5b600091825260209091200154905081565b60005473ffffffffffffffffffffffffffffffffffffffff16331480612607575060095473ffffffffffffffffffffffffffffffffffffffff1633145b61266d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b00000000000000000000006044820152606401610e43565b60265460ff166126fc5760065473ffffffffffffffffffffffffffffffffffffffff908116908316036126fc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f4e6f7420696e206d6967726174696f6e000000000000000000000000000000006044820152606401610e43565b6000546040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9182166004820152602481018390529083169063a9059cbb906044016020604051808303816000875af1158015612775573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127999190615892565b506040805173ffffffffffffffffffffffffffffffffffffffff84168152602081018390527f8c1256b8896378cd5044f80c202f9772b9d77dc85c8a6eb51967210b09bfaa2891015b60405180910390a15050565b73ffffffffffffffffffffffffffffffffffffffff8116600090815260216020526040812054908061281f84611707565b73ffffffffffffffffffffffffffffffffffffffff8516600090815260208052604081205491935090158015612878575073ffffffffffffffffffffffffffffffffffffffff8516600090815260216020526040902054155b806128a8575073ffffffffffffffffffffffffffffffffffffffff85166000908152601260205260409020548310155b156128b45750816128f4565b73ffffffffffffffffffffffffffffffffffffffff85166000908152601260205260409020546002906128e7908561587f565b6128f191906157ae565b90505b6000915060005b73ffffffffffffffffffffffffffffffffffffffff8616600090815260236020526040902054811015612a115773ffffffffffffffffffffffffffffffffffffffff8616600090815260236020526040812080548390811061295f5761295f615739565b90600052602060002090600502016040518060a001604052908160008201548152602001600182015481526020016002820154815260200160038201548152602001600482015481525050905060006129b888846120ee565b60408301519091506000670de0b6b3a76400006129d5878561587f565b6129df9084615797565b6129e991906157ae565b6129f3908361587f565b90506129ff818861587f565b965050600190930192506128fb915050565b50509193909250565b6002805403612a85576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610e43565b6002805560265462010000900460ff1615612afc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f5769746864726177616c732070617573656400000000000000000000000000006044820152606401610e43565b6111fb33338484614775565b60005473ffffffffffffffffffffffffffffffffffffffff16331480612b45575060095473ffffffffffffffffffffffffffffffffffffffff1633145b612bab576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b00000000000000000000006044820152606401610e43565b600a80547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b60005473ffffffffffffffffffffffffffffffffffffffff16331480612c2f575060095473ffffffffffffffffffffffffffffffffffffffff1633145b612c95576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b00000000000000000000006044820152606401610e43565b73ffffffffffffffffffffffffffffffffffffffff16600090815260246020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b60005473ffffffffffffffffffffffffffffffffffffffff16331480612d21575060095473ffffffffffffffffffffffffffffffffffffffff1633145b612d87576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b00000000000000000000006044820152606401610e43565b602680547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00811660ff90911615179055565b601781815481106125b957600080fd5b60005473ffffffffffffffffffffffffffffffffffffffff16331480612e06575060095473ffffffffffffffffffffffffffffffffffffffff1633145b612e6c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b00000000000000000000006044820152606401610e43565b6001821015612ed7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f4d756c206d61782074696d65206d757374206265203e3d2031000000000000006044820152606401610e43565b6001811015612f42576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f4d756c206d696e2074696d65206d757374206265203e3d2031000000000000006044820152606401610e43565b600e829055600f8190556040518281527f0e3e3fae480c6f92291358a02bc83f04ee1971d5488596bffda7929d57ab470f9060200160405180910390a16040518181527f0534d208d75dfdbfacc1204745dd9b3c4c37e8cfc05eb5e8e3ae538aedb0a9fa906020016127e2565b600280540361301a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610e43565b6002805533600161302d82826000614aa2565b602654640100000000900460ff16156130a2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f5374616b696e67207061757365640000000000000000000000000000000000006044820152606401610e43565b6000806130af3387614bfd565b9150915060008583604001516130c5919061587f565b90506006546130ec9073ffffffffffffffffffffffffffffffffffffffff16333089614db8565b6040805160a08101825288815260208581015181830152818301849052606080870151908301526080808701519083015233600090815260239091529190912080548490811061313e5761313e615739565b9060005260206000209060050201600082015181600001556020820151816001015560408201518160020155606082015181600301556080820151816004015590505085601e6000828254613193919061587f565b9091555050336000908152602080526040812080548892906131b690849061587f565b909155506131c990503360006001614aa2565b604080518881526020810188905233917f2640b32e7e5d0fa2a21ea06b22fbd75fda0fda384a895a5fdeef43646de47a0c910160405180910390a2505060016002555050505050565b60005473ffffffffffffffffffffffffffffffffffffffff1633148061324f575060095473ffffffffffffffffffffffffffffffffffffffff1633145b6132b5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b00000000000000000000006044820152606401610e43565b600980547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b6000806000806000600560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa158015613371573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061339591906158c9565b945094505093509350600083121580156133ae57508115155b80156133d257508369ffffffffffffffffffff168169ffffffffffffffffffff1610155b613438576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f496e76616c696420636861696e6c696e6b2070726963650000000000000000006044820152606401610e43565b50909392505050565b60045460609067ffffffffffffffff81111561345f5761345f61570a565b604051908082528060200260200182016040528015613488578160200160208202803683370190505b509050601e546000148061349c5750601f54155b156134f75760198054806020026020016040519081016040528092919081815260200182805480156134ed57602002820191906000526020600020905b8154815260200190600101908083116134d9575b5050505050905090565b60005b6004548110156115165761357a61354e601f54610d6b670de0b6b3a76400006117e56013878154811061352f5761352f615739565b90600052602060002001546117e5600c54613548614f4e565b90613e3e565b6019838154811061356157613561615739565b9060005260206000200154613f8190919063ffffffff16565b82828151811061358c5761358c615739565b60209081029190910101526001016134fa565b60005473ffffffffffffffffffffffffffffffffffffffff163314806135dc575060095473ffffffffffffffffffffffffffffffffffffffff1633145b613642576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b00000000000000000000006044820152606401610e43565b602680547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffff8116620100009182900460ff1615909102179055565b60028054036136e8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610e43565b600280553360016136fb82826000614aa2565b602654640100000000900460ff1615613770576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f5374616b696e67207061757365640000000000000000000000000000000000006044820152606401610e43565b60008061377d3387614bfd565b915091504285116137ea576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4d75737420626520696e207468652066757475726500000000000000000000006044820152606401610e43565b6000428360600151116137fe57600061380e565b42836060015161380e919061586c565b9050600061381c428861586c565b9050818111613887576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f43616e6e6f742073686f7274656e206c6f636b2074696d6500000000000000006044820152606401610e43565b600f548110156138f3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f4d696e696d756d207374616b652074696d65206e6f74206d65740000000000006044820152606401610e43565b600e5481111561395f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f547279696e6720746f206c6f636b20666f7220746f6f206c6f6e6700000000006044820152606401610e43565b6040518060a001604052808981526020014281526020018560400151815260200188815260200161398f83610e93565b90523360009081526023602052604090208054859081106139b2576139b2615739565b90600052602060002090600502016000820151816000015560208201518160010155604082015181600201556060820151816003015560808201518160040155905050613a023360006001614aa2565b6040805189815260208101839052428183015260608101899052905133917fc2cf1aae6decacbc52f96b4e4fec96d4ebab5236e4ed987165537bc463014a43919081900360800190a250506001600255505050505050565b73ffffffffffffffffffffffffffffffffffffffff81166000908152602080526040812054610eb990670de0b6b3a764000090610d6b906117e5611acb565b60005473ffffffffffffffffffffffffffffffffffffffff16331480613ad6575060095473ffffffffffffffffffffffffffffffffffffffff1633145b613b3c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b00000000000000000000006044820152606401610e43565b602680547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff81166101009182900460ff1615909102179055565b60265460ff161515600114613be7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f4e6f7420696e206d6967726174696f6e000000000000000000000000000000006044820152606401610e43565b73ffffffffffffffffffffffffffffffffffffffff8216600090815260256020908152604080832033845290915290205460ff168015613c3657503360009081526024602052604090205460ff165b613c9c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f4d69672e20696e76616c6964206f7220756e617070726f7665640000000000006044820152606401610e43565b613ca98233836001614775565b5050565b73ffffffffffffffffffffffffffffffffffffffff811660009081526024602052604090205460ff16613d3c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f496e76616c6964206d69677261746f72206164647265737300000000000000006044820152606401610e43565b33600090815260256020908152604080832073ffffffffffffffffffffffffffffffffffffffff9490941683529290522080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b601381815481106125b957600080fd5b6026546601000000000000900460ff16613e1e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f436f6e7472616374206e6f7420696e697469616c697a656400000000000000006044820152606401610e43565b613e26614f61565b42600c819055601654613e399190613f81565b600b55565b6000613e8083836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f7700008152506152f2565b9392505050565b600082600003613e9957506000610eb9565b6000613ea58385615797565b905082613eb285836157ae565b14613e80576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602160248201527f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f60448201527f77000000000000000000000000000000000000000000000000000000000000006064820152608401610e43565b6000613e8083836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250615346565b600080613f8e838561587f565b905083811015613e80576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f7700000000006044820152606401610e43565b60008183106140095781613e80565b5090919050565b84600161401f82826000614aa2565b602654640100000000900460ff16158061404d57503360009081526024602052604090205460ff1615156001145b6140b3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f5374616b696e6720706175736564206f7220696e206d6967726174696f6e00006044820152606401610e43565b6000851161411d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f4d757374207374616b65206d6f7265207468616e207a65726f000000000000006044820152606401610e43565b600f54841015614189576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f4d696e696d756d207374616b652074696d65206e6f74206d65740000000000006044820152606401610e43565b600e548411156141f5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f547279696e6720746f206c6f636b20666f7220746f6f206c6f6e6700000000006044820152606401610e43565b600061420085610e93565b73ffffffffffffffffffffffffffffffffffffffff89166000908152602080805260408083205490517fffffffffffffffffffffffffffffffffffffffff00000000000000000000000060608e901b169281019290925260348201889052605482018a9052607482015291925090609401604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152828252805160209182012073ffffffffffffffffffffffffffffffffffffffff8d1660009081526023835283902060a0850184528185529184018990529183018a905290925090606081016142f1888a613f81565b81526020908101859052825460018181018555600094855293829020835160059092020190815590820151928101929092556040810151600283015560608101516003830155608001516004909101556006546143669073ffffffffffffffffffffffffffffffffffffffff1689308a614db8565b601e546143739088613f81565b601e5573ffffffffffffffffffffffffffffffffffffffff891660009081526020805260409020546143a59088613f81565b73ffffffffffffffffffffffffffffffffffffffff8a1660009081526020805260408120919091556143da908a906001614aa2565b604080518881526020810188905290810182905273ffffffffffffffffffffffffffffffffffffffff89811660608301528a16907ff400e72e69ef4402819dfc57eeddc66f5eb69bf405e0e8098b1946ec1ac14a229060800160405180910390a2505050505050505050565b606082600161445782826000614aa2565b60045467ffffffffffffffff8111156144725761447261570a565b60405190808252806020026020018201604052801561449b578160200160208202803683370190505b50925060005b6004548110156147455773ffffffffffffffffffffffffffffffffffffffff86166000908152601b6020908152604080832084845290915290205484518590839081106144f0576144f0615739565b602002602001018181525050600084828151811061451057614510615739565b6020026020010151111561473d5773ffffffffffffffffffffffffffffffffffffffff86166000908152601b60209081526040808320848452909152812055600480548290811061456357614563615739565b9060005260206000200160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a9059cbb868684815181106145bc576145bc615739565b60200260200101516040518363ffffffff1660e01b815260040161460292919073ffffffffffffffffffffffffffffffffffffffff929092168252602082015260400190565b6020604051808303816000875af1158015614621573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906146459190615892565b5083818151811061465857614658615739565b60200260200101516018828154811061467357614673615739565b90600052602060002001600082825461468c919061587f565b925050819055508573ffffffffffffffffffffffffffffffffffffffff167f1d2f2ca53af5d2f333bd32fdd45f9c52ad8ebe31414f7792912077fcb3876dff8583815181106146dd576146dd615739565b6020026020010151600484815481106146f8576146f8615739565b600091825260209182902001546040805193845273ffffffffffffffffffffffffffffffffffffffff9182169284019290925289169082015260600160405180910390a25b6001016144a1565b50505073ffffffffffffffffffffffffffffffffffffffff9092166000908152601d602052604090204290555090565b808061478d575060265465010000000000900460ff16155b156147a25761479c8484614446565b506147af565b6147af8460016000614aa2565b6000806147bc8685614bfd565b81519193509150841461482b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f5374616b65206e6f7420666f756e6400000000000000000000000000000000006044820152606401610e43565b81606001514210158061484b575060265460ff6101009091041615156001145b8061486a57503360009081526024602052604090205460ff1615156001145b6148d0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f5374616b65206973207374696c6c206c6f636b656421000000000000000000006044820152606401610e43565b60408201518015614a9957601e546148e89082613e3e565b601e5573ffffffffffffffffffffffffffffffffffffffff8716600090815260208052604090205461491a9082613e3e565b73ffffffffffffffffffffffffffffffffffffffff881660009081526020808052604080832093909355602390522080548390811061495b5761495b615739565b9060005260206000209060050201600080820160009055600182016000905560028201600090556003820160009055600482016000905550506149a087600180614aa2565b6006546040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8881166004830152602482018490529091169063a9059cbb906044016020604051808303816000875af1158015614a19573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614a3d9190615892565b50604080518281526020810187905273ffffffffffffffffffffffffffffffffffffffff888116828401529151918916917f1d9308f6b22a2754a1c622bb30889e8f8f956c83e524d039e9d65d5f052eb9089181900360600190a25b50505050505050565b8115614ab057614ab0613da8565b8015614ae657614abf83611707565b73ffffffffffffffffffffffffffffffffffffffff84166000908152601260205260409020555b73ffffffffffffffffffffffffffffffffffffffff831615614bf8576000806000614b10866127ee565b925092509250614b1f8661538e565b73ffffffffffffffffffffffffffffffffffffffff86166000908152601260205260409020829055828110614ba3576000614b5a8285613e3e565b601f54909150614b6a9082613f81565b601f55614b778482613f81565b73ffffffffffffffffffffffffffffffffffffffff881660009081526021602052604090205550614bf4565b6000614baf8483613e3e565b601f54909150614bbf9082613e3e565b601f55614bcc8482613e3e565b73ffffffffffffffffffffffffffffffffffffffff8816600090815260216020526040902055505b5050505b505050565b614c326040518060a0016040528060008019168152602001600081526020016000815260200160008152602001600081525090565b6000805b73ffffffffffffffffffffffffffffffffffffffff8516600090815260236020526040902054811015614d465773ffffffffffffffffffffffffffffffffffffffff85166000908152602360205260409020805482908110614c9a57614c9a615739565b9060005260206000209060050201600001548403614d3e5773ffffffffffffffffffffffffffffffffffffffff85166000908152602360205260409020805482908110614ce957614ce9615739565b90600052602060002090600502016040518060a0016040529081600082015481526020016001820154815260200160028201548152602001600382015481526020016004820154815250509250809150614d46565b600101614c36565b5081518314614db1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f5374616b65206e6f7420666f756e6400000000000000000000000000000000006044820152606401610e43565b9250929050565b6040805173ffffffffffffffffffffffffffffffffffffffff85811660248301528481166044830152606480830185905283518084039091018152608490920183526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f23b872dd000000000000000000000000000000000000000000000000000000001790529151600092839290881691614e579190615919565b6000604051808303816000865af19150503d8060008114614e94576040519150601f19603f3d011682016040523d82523d6000602084013e614e99565b606091505b5091509150818015614ec3575080511580614ec3575080806020019051810190614ec39190615892565b614bf4576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f5472616e7366657248656c7065723a205452414e534645525f46524f4d5f464160448201527f494c4544000000000000000000000000000000000000000000000000000000006064820152608401610e43565b6000614f5c42600b54613ffa565b905090565b601654601c54614f72904290613e3e565b106150b25760075473ffffffffffffffffffffffffffffffffffffffff161561502a57600760009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16638f73c5ae6040518163ffffffff1660e01b81526004016020604051808303816000875af1158015615004573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061502891906157e9565b505b6006546040517fc00007b000000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff9091169063c00007b090602401600060405180830381600087803b15801561509557600080fd5b505af11580156150a9573d6000803e3d6000fd5b505042601c5550505b60006150d46150cc600c5442613e3e90919063ffffffff16565b601654613ffa565b905060006150e0613441565b905060005b600454811015614bf85760006004828154811061510457615104615739565b6000918252602090912001546040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff909116906370a0823190602401602060405180830381865afa15801561517b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061519f91906157e9565b90506151b884601384815481106114d8576114d8615739565b601783815481106151cb576151cb615739565b9060005260206000200160008282546151e4919061587f565b925050819055508282815181106151fd576151fd615739565b60200260200101516019838154811061521857615218615739565b906000526020600020018190555060006152756018848154811061523e5761523e615739565b90600052602060002001546017858154811061525c5761525c615739565b9060005260206000200154613e3e90919063ffffffff16565b90508082116152a45760006013848154811061529357615293615739565b6000918252602090912001556152e8565b60006152b08383613e3e565b90506152c760165482613f3f90919063ffffffff16565b601385815481106152da576152da615739565b600091825260209091200155505b50506001016150e5565b60008184841115615330576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610e4391906155f5565b50600061533d848661586c565b95945050505050565b60008183615381576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610e4391906155f5565b50600061533d84866157ae565b73ffffffffffffffffffffffffffffffffffffffff8116156154675760006153b582610bec565b905060005b600454811015614bf8578181815181106153d6576153d6615739565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff85166000908152601b835260408082208583529093529190912055601980548290811061542657615426615739565b600091825260208083209091015473ffffffffffffffffffffffffffffffffffffffff86168352601a825260408084208585529092529120556001016153ba565b50565b73ffffffffffffffffffffffffffffffffffffffff8116811461546757600080fd5b60006020828403121561549e57600080fd5b8135613e808161546a565b6020808252825182820181905260009190848201906040850190845b818110156154e1578351835292840192918401916001016154c5565b50909695505050505050565b6000602082840312156154ff57600080fd5b5035919050565b6000806040838503121561551957600080fd5b50508035926020909101359150565b602080825282518282018190526000919060409081850190868401855b828110156155895781518051855286810151878601528581015186860152606080820151908601526080908101519085015260a09093019290850190600101615545565b5091979650505050505050565b600080600080608085870312156155ac57600080fd5b84356155b78161546a565b966020860135965060408601359560600135945092505050565b60005b838110156155ec5781810151838201526020016155d4565b50506000910152565b60208152600082518060208401526156148160408501602087016155d1565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169190910160400192915050565b60008060006060848603121561565b57600080fd5b505081359360208301359350604090920135919050565b6000806040838503121561568557600080fd5b82356156908161546a565b946020939093013593505050565b801515811461546757600080fd5b600080604083850312156156bf57600080fd5b8235915060208301356156d18161569e565b809150509250929050565b600080604083850312156156ef57600080fd5b82356156fa8161546a565b915060208301356156d18161546a565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b8082028115828204841417610eb957610eb9615768565b6000826157e4577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b6000602082840312156157fb57600080fd5b5051919050565b600181811c9082168061581657607f821691505b602082108103610c96577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b60006020828403121561586157600080fd5b8151613e808161546a565b81810381811115610eb957610eb9615768565b80820180821115610eb957610eb9615768565b6000602082840312156158a457600080fd5b8151613e808161569e565b805169ffffffffffffffffffff81168114610d9f57600080fd5b600080600080600060a086880312156158e157600080fd5b6158ea866158af565b945060208601519350604086015192506060860151915061590d608087016158af565b90509295509295909350565b6000825161592b8184602087016155d1565b919091019291505056fea2646970667358221220e4716ab1889f316057138fe44c637fd8d9c0ea22572601847b8dc238ae47ebc764736f6c63430008170033000000000000000000000000ba079be8f77c8c989cc5a575e8fd010efc8ee48400000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000d2d8beb901f90163be4667a85cddebb7177eb3e300000000000000000000000017fc002b466eec40dae837fc4be5c67993ddbd6f000000000000000000000000e61d9ed1e5dc261d1e90a99304fadcef2c76fd10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000009d2f299715d94d8a7e6f5eaa8e654e8c74a988a700000000000000000000000011cdb42b0eb46d95f990bedd4695a6e3fa034978000000000000000000000000aafcfd42c9954c6689ef1901e03db742520829c5000000000000000000000000912ce59144191c1204e64559fe8253a0e49e6548
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106105495760003560e01c80637b31c19a116102bc578063c8f33c9111610186578063e9f2838e116100e3578063f288baf611610097578063f2caeb1e1161007c578063f2caeb1e14610bc4578063fce6fd1314610bd7578063fff6cae914610be457600080fd5b8063f288baf614610bb2578063f2a8d34914610bbb57600080fd5b8063ebe2b12b116100c8578063ebe2b12b14610b73578063ee89e02f14610b7c578063f12f144714610b9f57600080fd5b8063e9f2838e14610b4d578063eb3c209e14610b6057600080fd5b8063d42fc9b41161013a578063dcc3e06e1161011f578063dcc3e06e14610b1d578063e01f62bf14610b3d578063e1ba95d214610b4557600080fd5b8063d42fc9b414610ad5578063d9f96e8d14610ae857600080fd5b8063cdc82e801161016b578063cdc82e8014610ab1578063d239f00314610aba578063d2fbdc0d14610ac257600080fd5b8063c8f33c9114610aa0578063cd3daf9d14610aa957600080fd5b80639b8c15a811610234578063b85efd06116101e8578063bbb781cc116101cd578063bbb781cc14610a70578063bdacb30314610a85578063bdb123e314610a9857600080fd5b8063b85efd0614610a54578063b94c4dcb14610a6757600080fd5b8063a2217bc511610219578063a2217bc514610a26578063a65fd70a14610a2e578063af00f4e214610a4157600080fd5b80639b8c15a8146109e55780639c5303eb14610a1357600080fd5b80638bad86a71161028b578063903bd2af11610270578063903bd2af146109ad57806392eefe9b146109c05780639637927f146109d357600080fd5b80638bad86a71461095f5780638da5cb5b1461098d57600080fd5b80637b31c19a1461091e5780637bb7bed114610926578063818a2ba6146109395780638980f11f1461094c57600080fd5b80633b8105b31161041857806364f2c0601161037557806372f702f311610329578063774d4ae71161030e578063774d4ae7146108c85780637970833e146108db57806379ba50971461091657600080fd5b806372f702f314610895578063741d3c18146108b557600080fd5b80636ce46bc31161035a5780636ce46bc3146108705780636cea0b0d146108835780636e27cef91461088c57600080fd5b806364f2c06014610848578063693392451461085057600080fd5b80634fd2b536116103cc57806353a47bb7116103b157806353a47bb71461081857806354fd4d50146108385780635bfd92581461084057600080fd5b80634fd2b5361461079e57806352732bc8146107b157600080fd5b806341edbdf0116103fd57806341edbdf0146107495780634b24ea471461075e5780634bc66f321461077e57600080fd5b80633b8105b3146107395780633d18b9121461074157600080fd5b80631b3e870a116104c65780632c0c2a0a1161047a57806336f89af21161045f57806336f89af2146106e3578063386a952514610719578063392e53cd1461072257600080fd5b80632c0c2a0a146106bc578063323331ca146106cf57600080fd5b80631e090f01116104ab5780631e090f011461066357806328ef934e146106835780632bd59b631461069657600080fd5b80631b3e870a146106485780631c1f78eb1461065b57600080fd5b8063169d27ef1161051d57806317b18c891161050257806317b18c891461060d57806318c971ae1461062057806319ff52fd1461062857600080fd5b8063169d27ef146105c0578063174ed0ca146105c857600080fd5b80628cc2621461054e578063046e7d3f146105775780630d7bac4f1461058c5780631627540c146105ad575b600080fd5b61056161055c36600461548c565b610bec565b60405161056e91906154a9565b60405180910390f35b61058a61058536600461548c565b610da4565b005b61059f61059a3660046154ed565b610e93565b60405190815260200161056e565b61058a6105bb36600461548c565b610ebf565b61058a610fdf565b6008546105e89073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161056e565b61058a61061b366004615506565b61117f565b61058a611204565b6003546105e89073ffffffffffffffffffffffffffffffffffffffff1681565b61058a61065636600461548c565b6112e5565b610561611468565b61067661067136600461548c565b61151a565b60405161056e9190615528565b61058a610691366004615596565b6115ce565b6026546106ac9065010000000000900460ff1681565b604051901515815260200161056e565b61059f6106ca36600461548c565b611707565b6026546106ac906301000000900460ff1681565b61059f6106f136600461548c565b73ffffffffffffffffffffffffffffffffffffffff1660009081526021602052604090205490565b61059f60165481565b6026546106ac906601000000000000900460ff1681565b61058a61183a565b61056161191a565b610751611a13565b60405161056e91906155f5565b600a546105e89073ffffffffffffffffffffffffffffffffffffffff1681565b6009546105e89073ffffffffffffffffffffffffffffffffffffffff1681565b61059f6107ac36600461548c565b611aa1565b61058a6107bf36600461548c565b33600090815260256020908152604080832073ffffffffffffffffffffffffffffffffffffffff9490941683529290522080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055565b6001546105e89073ffffffffffffffffffffffffffffffffffffffff1681565b610751611abe565b61059f611acb565b601f5461059f565b61059f61085e36600461548c565b60156020526000908152604090205481565b61058a61087e366004615646565b611d26565b61059f601c5481565b61059f600f5481565b6006546105e89073ffffffffffffffffffffffffffffffffffffffff1681565b61058a6108c336600461548c565b611f87565b61059f6108d6366004615672565b6120ee565b6108ee6108e9366004615672565b6122fa565b604080519586526020860194909452928401919091526060830152608082015260a00161056e565b61058a612348565b61058a612493565b6105e86109343660046154ed565b612572565b61059f6109473660046154ed565b6125a9565b61058a61095a366004615672565b6125ca565b61097261096d36600461548c565b6127ee565b6040805193845260208401929092529082015260600161056e565b6000546105e89073ffffffffffffffffffffffffffffffffffffffff1681565b61058a6109bb3660046156ac565b612a1a565b61058a6109ce36600461548c565b612b08565b6026546106ac90610100900460ff1681565b6106ac6109f33660046156dc565b602560209081526000928352604080842090915290825290205460ff1681565b61058a610a2136600461548c565b612bf2565b61058a612ce4565b61059f610a3c3660046154ed565b612db9565b61058a610a4f366004615506565b612dc9565b61058a610a62366004615506565b612faf565b61059f600e5481565b6026546106ac90640100000000900460ff1681565b61058a610a9336600461548c565b613212565b61059f6132fc565b61059f600c5481565b610561613441565b61059f600d5481565b61058a61359f565b61058a610ad0366004615506565b61367d565b61059f610ae336600461548c565b613a5a565b61059f610af636600461548c565b73ffffffffffffffffffffffffffffffffffffffff16600090815260208052604090205490565b6007546105e89073ffffffffffffffffffffffffffffffffffffffff1681565b601e5461059f565b61058a613a99565b6026546106ac9062010000900460ff1681565b61058a610b6e366004615672565b613b76565b61059f600b5481565b6106ac610b8a36600461548c565b60246020526000908152604090205460ff1681565b61058a610bad36600461548c565b613cad565b61059f60115481565b61059f60105481565b61059f610bd23660046154ed565b613d98565b6026546106ac9060ff1681565b61058a613da8565b60045460609067ffffffffffffffff811115610c0a57610c0a61570a565b604051908082528060200260200182016040528015610c33578160200160208202803683370190505b5073ffffffffffffffffffffffffffffffffffffffff831660009081526021602052604081205491925003610c9c5760005b600454811015610c96576000828281518110610c8357610c83615739565b6020908102919091010152600101610c65565b50919050565b6000610ca6613441565b905060005b600454811015610d9c5773ffffffffffffffffffffffffffffffffffffffff84166000818152601b60209081526040808320858452825280832054938352601a82528083208584529091529020548351610d779291610d7191670de0b6b3a764000091610d6b91610d3f9190899089908110610d2957610d29615739565b6020026020010151613e3e90919063ffffffff16565b73ffffffffffffffffffffffffffffffffffffffff8a1660009081526021602052604090205490613e87565b90613f3f565b90613f81565b838281518110610d8957610d89615739565b6020908102919091010152600101610cab565b50505b919050565b60005473ffffffffffffffffffffffffffffffffffffffff16331480610de1575060095473ffffffffffffffffffffffffffffffffffffffff1633145b610e4c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b000000000000000000000060448201526064015b60405180910390fd5b600380547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b600d54600e54600091610eb991610eaa8286615797565b610eb491906157ae565b613ffa565b92915050565b60005473ffffffffffffffffffffffffffffffffffffffff163314610f66576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602f60248201527f4f6e6c792074686520636f6e7472616374206f776e6572206d6179207065726660448201527f6f726d207468697320616374696f6e00000000000000000000000000000000006064820152608401610e43565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040519081527f906a1c6bd7e3091ea86693dd029a831c19049ce77f1dce2ce0bab1cacbabce229060200160405180910390a150565b60005473ffffffffffffffffffffffffffffffffffffffff1633148061101c575060095473ffffffffffffffffffffffffffffffffffffffff1633145b8061103e5750600a5473ffffffffffffffffffffffffffffffffffffffff1633145b6110a4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4e6f74206f776e2c20746c6b2c206f72206374726c72000000000000000000006044820152606401610e43565b6026546601000000000000900460ff161561111b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f416c726561647920696e697469616c697a6564000000000000000000000000006044820152606401610e43565b602680547fffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffff166601000000000000179055611154613da8565b6040517fb5cfe3ccd03847076864f081609024cbc2eb98c38da4d8b2cebe9479a9a1ef3790600090a1565b60028054036111ea576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610e43565b600280556111fb3380848442614010565b50506001600255565b60005473ffffffffffffffffffffffffffffffffffffffff16331480611241575060095473ffffffffffffffffffffffffffffffffffffffff1633145b6112a7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b00000000000000000000006044820152606401610e43565b602680547fffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffffff8116650100000000009182900460ff1615909102179055565b60005473ffffffffffffffffffffffffffffffffffffffff16331480611322575060095473ffffffffffffffffffffffffffffffffffffffff1633145b611388576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b00000000000000000000006044820152606401610e43565b73ffffffffffffffffffffffffffffffffffffffff811660009081526024602052604090205460ff16151560011461141c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f41646472657373206e6f6e6578697374656e74000000000000000000000000006044820152606401610e43565b73ffffffffffffffffffffffffffffffffffffffff16600090815260246020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055565b60045460609067ffffffffffffffff8111156114865761148661570a565b6040519080825280602002602001820160405280156114af578160200160208202803683370190505b50905060005b600454811015611516576114f1601654601383815481106114d8576114d8615739565b9060005260206000200154613e8790919063ffffffff16565b82828151811061150357611503615739565b60209081029190910101526001016114b5565b5090565b73ffffffffffffffffffffffffffffffffffffffff81166000908152602360209081526040808320805482518185028101850190935280835260609492939192909184015b828210156115c357838290600052602060002090600502016040518060a0016040529081600082015481526020016001820154815260200160028201548152602001600382015481526020016004820154815250508152602001906001019061155f565b505050509050919050565b60265460ff16151560011461163f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f4e6f7420696e206d6967726174696f6e000000000000000000000000000000006044820152606401610e43565b73ffffffffffffffffffffffffffffffffffffffff8416600090815260256020908152604080832033845290915290205460ff16801561168e57503360009081526024602052604090205460ff165b6116f4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f4d69672e20696e76616c6964206f7220756e617070726f7665640000000000006044820152606401610e43565b6117018433858585614010565b50505050565b60035460009073ffffffffffffffffffffffffffffffffffffffff161561183257600061173383611aa1565b90508015611829576003546040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85811660048301526000926117eb928592610d6b92670de0b6b3a7640000929116906370a0823190602401602060405180830381865afa1580156117c1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117e591906157e9565b90613e87565b90506000611810670de0b6b3a7640000610d6b60115485613e8790919063ffffffff16565b905060115481111561182157506011545b949350505050565b50600092915050565b506000919050565b60005473ffffffffffffffffffffffffffffffffffffffff16331480611877575060095473ffffffffffffffffffffffffffffffffffffffff1633145b6118dd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b00000000000000000000006044820152606401610e43565b602680547fffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffff81166401000000009182900460ff1615909102179055565b60606002805403611987576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610e43565b600280556026546301000000900460ff16156119ff576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f5265776172647320636f6c6c656374696f6e20706175736564000000000000006044820152606401610e43565b611a093333614446565b9050600160025590565b60288054611a2090615802565b80601f0160208091040260200160405190810160405280929190818152602001828054611a4c90615802565b8015611a995780601f10611a6e57610100808354040283529160200191611a99565b820191906000526020600020905b815481529060010190602001808311611a7c57829003601f168201915b505050505081565b6000610eb9670de0b6b3a7640000610d6b6010546117e586613a5a565b60278054611a2090615802565b6000806000600660009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663280718e26040518163ffffffff1660e01b8152600401602060405180830381865afa158015611b3d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b61919061584f565b905060008173ffffffffffffffffffffffffffffffffffffffff166382c630666040518163ffffffff1660e01b8152600401602060405180830381865afa158015611bb0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bd4919061584f565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8216600482015290915060009073178412e79c25968a32e89b11f63b33f733770c2a906370a0823190602401602060405180830381865afa158015611c58573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c7c91906157e9565b905060008273ffffffffffffffffffffffffffffffffffffffff166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611ccb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cef91906157e9565b611cf76132fc565b611d019084615797565b611d0b91906157ae565b9050611d1c816402540be400615797565b9695505050505050565b60005473ffffffffffffffffffffffffffffffffffffffff16331480611d63575060095473ffffffffffffffffffffffffffffffffffffffff1633145b611dc9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b00000000000000000000006044820152606401610e43565b670de0b6b3a7640000831015611e60576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f4d756c74206d757374206265203e3d204d554c5449504c4945525f505245434960448201527f53494f4e000000000000000000000000000000000000000000000000000000006064820152608401610e43565b60008111611eca576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f766546585320706374206d6178206d757374206265203e3d20300000000000006044820152606401610e43565b600d839055601182905560108190556040518281527fc9d56ccdd6b954d8d74700db074cc667054f8e33c1b8d23e97021d4c588a87619060200160405180910390a17fa1676084a9eea08c6f205b60799323b364a1bd8e10aba89f0fbd94cfbf68b5dd600d54604051611f3f91815260200190565b60405180910390a17f58c7ececaeb4704a0039e0d22c1b618367f7a7b9a4e191ab9baed34898f63f2e601054604051611f7a91815260200190565b60405180910390a1505050565b60005473ffffffffffffffffffffffffffffffffffffffff16331480611fc4575060095473ffffffffffffffffffffffffffffffffffffffff1633145b61202a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b00000000000000000000006044820152606401610e43565b73ffffffffffffffffffffffffffffffffffffffff81166120a7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f5a65726f206164647265737320646574656374656400000000000000000000006044820152606401610e43565b600580547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b73ffffffffffffffffffffffffffffffffffffffff8216600090815260236020526040812080548291908490811061212857612128615739565b600091825260208083206040805160a081018252600590940290910180548452600181015484840181905260028201548584015260038201546060860152600490910154608085015273ffffffffffffffffffffffffffffffffffffffff89168552601d90925283205491935011156121a6575060208101516121ce565b5073ffffffffffffffffffffffffffffffffffffffff84166000908152601d60205260409020545b4282606001511161228e57606082015173ffffffffffffffffffffffffffffffffffffffff86166000908152601d6020526040902054101561228557600081836060015161221c919061586c565b90506000836060015142612230919061586c565b9050600061224261059a6002856157ae565b905060006122508382615797565b61225a8584615797565b612264919061587f565b9050612270838561587f565b61227a90826157ae565b9650505050506122de565b600092506122de565b6000808284606001516122a1919061586c565b905060004285606001516122b5919061586c565b905060026122c3828461587f565b6122cd91906157ae565b925050506122da81610e93565b9350505b81608001518311156122f257816080015192505b505092915050565b6023602052816000526040600020818154811061231657600080fd5b600091825260209091206005909102018054600182015460028301546003840154600490940154929550909350919085565b60015473ffffffffffffffffffffffffffffffffffffffff1633146123ef576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603560248201527f596f75206d757374206265206e6f6d696e61746564206265666f726520796f7560448201527f2063616e20616363657074206f776e65727368697000000000000000000000006064820152608401610e43565b6000546001546040805173ffffffffffffffffffffffffffffffffffffffff93841681529290911660208301527fb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159c910160405180910390a160018054600080547fffffffffffffffffffffffff000000000000000000000000000000000000000090811673ffffffffffffffffffffffffffffffffffffffff841617909155169055565b60005473ffffffffffffffffffffffffffffffffffffffff163314806124d0575060095473ffffffffffffffffffffffffffffffffffffffff1633145b612536576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b00000000000000000000006044820152606401610e43565b602680547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffff811663010000009182900460ff1615909102179055565b6004818154811061258257600080fd5b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff16905081565b601881815481106125b957600080fd5b600091825260209091200154905081565b60005473ffffffffffffffffffffffffffffffffffffffff16331480612607575060095473ffffffffffffffffffffffffffffffffffffffff1633145b61266d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b00000000000000000000006044820152606401610e43565b60265460ff166126fc5760065473ffffffffffffffffffffffffffffffffffffffff908116908316036126fc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f4e6f7420696e206d6967726174696f6e000000000000000000000000000000006044820152606401610e43565b6000546040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9182166004820152602481018390529083169063a9059cbb906044016020604051808303816000875af1158015612775573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127999190615892565b506040805173ffffffffffffffffffffffffffffffffffffffff84168152602081018390527f8c1256b8896378cd5044f80c202f9772b9d77dc85c8a6eb51967210b09bfaa2891015b60405180910390a15050565b73ffffffffffffffffffffffffffffffffffffffff8116600090815260216020526040812054908061281f84611707565b73ffffffffffffffffffffffffffffffffffffffff8516600090815260208052604081205491935090158015612878575073ffffffffffffffffffffffffffffffffffffffff8516600090815260216020526040902054155b806128a8575073ffffffffffffffffffffffffffffffffffffffff85166000908152601260205260409020548310155b156128b45750816128f4565b73ffffffffffffffffffffffffffffffffffffffff85166000908152601260205260409020546002906128e7908561587f565b6128f191906157ae565b90505b6000915060005b73ffffffffffffffffffffffffffffffffffffffff8616600090815260236020526040902054811015612a115773ffffffffffffffffffffffffffffffffffffffff8616600090815260236020526040812080548390811061295f5761295f615739565b90600052602060002090600502016040518060a001604052908160008201548152602001600182015481526020016002820154815260200160038201548152602001600482015481525050905060006129b888846120ee565b60408301519091506000670de0b6b3a76400006129d5878561587f565b6129df9084615797565b6129e991906157ae565b6129f3908361587f565b90506129ff818861587f565b965050600190930192506128fb915050565b50509193909250565b6002805403612a85576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610e43565b6002805560265462010000900460ff1615612afc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f5769746864726177616c732070617573656400000000000000000000000000006044820152606401610e43565b6111fb33338484614775565b60005473ffffffffffffffffffffffffffffffffffffffff16331480612b45575060095473ffffffffffffffffffffffffffffffffffffffff1633145b612bab576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b00000000000000000000006044820152606401610e43565b600a80547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b60005473ffffffffffffffffffffffffffffffffffffffff16331480612c2f575060095473ffffffffffffffffffffffffffffffffffffffff1633145b612c95576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b00000000000000000000006044820152606401610e43565b73ffffffffffffffffffffffffffffffffffffffff16600090815260246020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b60005473ffffffffffffffffffffffffffffffffffffffff16331480612d21575060095473ffffffffffffffffffffffffffffffffffffffff1633145b612d87576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b00000000000000000000006044820152606401610e43565b602680547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00811660ff90911615179055565b601781815481106125b957600080fd5b60005473ffffffffffffffffffffffffffffffffffffffff16331480612e06575060095473ffffffffffffffffffffffffffffffffffffffff1633145b612e6c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b00000000000000000000006044820152606401610e43565b6001821015612ed7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f4d756c206d61782074696d65206d757374206265203e3d2031000000000000006044820152606401610e43565b6001811015612f42576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f4d756c206d696e2074696d65206d757374206265203e3d2031000000000000006044820152606401610e43565b600e829055600f8190556040518281527f0e3e3fae480c6f92291358a02bc83f04ee1971d5488596bffda7929d57ab470f9060200160405180910390a16040518181527f0534d208d75dfdbfacc1204745dd9b3c4c37e8cfc05eb5e8e3ae538aedb0a9fa906020016127e2565b600280540361301a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610e43565b6002805533600161302d82826000614aa2565b602654640100000000900460ff16156130a2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f5374616b696e67207061757365640000000000000000000000000000000000006044820152606401610e43565b6000806130af3387614bfd565b9150915060008583604001516130c5919061587f565b90506006546130ec9073ffffffffffffffffffffffffffffffffffffffff16333089614db8565b6040805160a08101825288815260208581015181830152818301849052606080870151908301526080808701519083015233600090815260239091529190912080548490811061313e5761313e615739565b9060005260206000209060050201600082015181600001556020820151816001015560408201518160020155606082015181600301556080820151816004015590505085601e6000828254613193919061587f565b9091555050336000908152602080526040812080548892906131b690849061587f565b909155506131c990503360006001614aa2565b604080518881526020810188905233917f2640b32e7e5d0fa2a21ea06b22fbd75fda0fda384a895a5fdeef43646de47a0c910160405180910390a2505060016002555050505050565b60005473ffffffffffffffffffffffffffffffffffffffff1633148061324f575060095473ffffffffffffffffffffffffffffffffffffffff1633145b6132b5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b00000000000000000000006044820152606401610e43565b600980547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b6000806000806000600560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa158015613371573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061339591906158c9565b945094505093509350600083121580156133ae57508115155b80156133d257508369ffffffffffffffffffff168169ffffffffffffffffffff1610155b613438576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f496e76616c696420636861696e6c696e6b2070726963650000000000000000006044820152606401610e43565b50909392505050565b60045460609067ffffffffffffffff81111561345f5761345f61570a565b604051908082528060200260200182016040528015613488578160200160208202803683370190505b509050601e546000148061349c5750601f54155b156134f75760198054806020026020016040519081016040528092919081815260200182805480156134ed57602002820191906000526020600020905b8154815260200190600101908083116134d9575b5050505050905090565b60005b6004548110156115165761357a61354e601f54610d6b670de0b6b3a76400006117e56013878154811061352f5761352f615739565b90600052602060002001546117e5600c54613548614f4e565b90613e3e565b6019838154811061356157613561615739565b9060005260206000200154613f8190919063ffffffff16565b82828151811061358c5761358c615739565b60209081029190910101526001016134fa565b60005473ffffffffffffffffffffffffffffffffffffffff163314806135dc575060095473ffffffffffffffffffffffffffffffffffffffff1633145b613642576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b00000000000000000000006044820152606401610e43565b602680547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffff8116620100009182900460ff1615909102179055565b60028054036136e8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610e43565b600280553360016136fb82826000614aa2565b602654640100000000900460ff1615613770576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f5374616b696e67207061757365640000000000000000000000000000000000006044820152606401610e43565b60008061377d3387614bfd565b915091504285116137ea576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4d75737420626520696e207468652066757475726500000000000000000000006044820152606401610e43565b6000428360600151116137fe57600061380e565b42836060015161380e919061586c565b9050600061381c428861586c565b9050818111613887576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f43616e6e6f742073686f7274656e206c6f636b2074696d6500000000000000006044820152606401610e43565b600f548110156138f3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f4d696e696d756d207374616b652074696d65206e6f74206d65740000000000006044820152606401610e43565b600e5481111561395f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f547279696e6720746f206c6f636b20666f7220746f6f206c6f6e6700000000006044820152606401610e43565b6040518060a001604052808981526020014281526020018560400151815260200188815260200161398f83610e93565b90523360009081526023602052604090208054859081106139b2576139b2615739565b90600052602060002090600502016000820151816000015560208201518160010155604082015181600201556060820151816003015560808201518160040155905050613a023360006001614aa2565b6040805189815260208101839052428183015260608101899052905133917fc2cf1aae6decacbc52f96b4e4fec96d4ebab5236e4ed987165537bc463014a43919081900360800190a250506001600255505050505050565b73ffffffffffffffffffffffffffffffffffffffff81166000908152602080526040812054610eb990670de0b6b3a764000090610d6b906117e5611acb565b60005473ffffffffffffffffffffffffffffffffffffffff16331480613ad6575060095473ffffffffffffffffffffffffffffffffffffffff1633145b613b3c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b00000000000000000000006044820152606401610e43565b602680547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff81166101009182900460ff1615909102179055565b60265460ff161515600114613be7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f4e6f7420696e206d6967726174696f6e000000000000000000000000000000006044820152606401610e43565b73ffffffffffffffffffffffffffffffffffffffff8216600090815260256020908152604080832033845290915290205460ff168015613c3657503360009081526024602052604090205460ff165b613c9c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f4d69672e20696e76616c6964206f7220756e617070726f7665640000000000006044820152606401610e43565b613ca98233836001614775565b5050565b73ffffffffffffffffffffffffffffffffffffffff811660009081526024602052604090205460ff16613d3c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f496e76616c6964206d69677261746f72206164647265737300000000000000006044820152606401610e43565b33600090815260256020908152604080832073ffffffffffffffffffffffffffffffffffffffff9490941683529290522080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b601381815481106125b957600080fd5b6026546601000000000000900460ff16613e1e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f436f6e7472616374206e6f7420696e697469616c697a656400000000000000006044820152606401610e43565b613e26614f61565b42600c819055601654613e399190613f81565b600b55565b6000613e8083836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f7700008152506152f2565b9392505050565b600082600003613e9957506000610eb9565b6000613ea58385615797565b905082613eb285836157ae565b14613e80576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602160248201527f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f60448201527f77000000000000000000000000000000000000000000000000000000000000006064820152608401610e43565b6000613e8083836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250615346565b600080613f8e838561587f565b905083811015613e80576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f7700000000006044820152606401610e43565b60008183106140095781613e80565b5090919050565b84600161401f82826000614aa2565b602654640100000000900460ff16158061404d57503360009081526024602052604090205460ff1615156001145b6140b3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f5374616b696e6720706175736564206f7220696e206d6967726174696f6e00006044820152606401610e43565b6000851161411d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f4d757374207374616b65206d6f7265207468616e207a65726f000000000000006044820152606401610e43565b600f54841015614189576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f4d696e696d756d207374616b652074696d65206e6f74206d65740000000000006044820152606401610e43565b600e548411156141f5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f547279696e6720746f206c6f636b20666f7220746f6f206c6f6e6700000000006044820152606401610e43565b600061420085610e93565b73ffffffffffffffffffffffffffffffffffffffff89166000908152602080805260408083205490517fffffffffffffffffffffffffffffffffffffffff00000000000000000000000060608e901b169281019290925260348201889052605482018a9052607482015291925090609401604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152828252805160209182012073ffffffffffffffffffffffffffffffffffffffff8d1660009081526023835283902060a0850184528185529184018990529183018a905290925090606081016142f1888a613f81565b81526020908101859052825460018181018555600094855293829020835160059092020190815590820151928101929092556040810151600283015560608101516003830155608001516004909101556006546143669073ffffffffffffffffffffffffffffffffffffffff1689308a614db8565b601e546143739088613f81565b601e5573ffffffffffffffffffffffffffffffffffffffff891660009081526020805260409020546143a59088613f81565b73ffffffffffffffffffffffffffffffffffffffff8a1660009081526020805260408120919091556143da908a906001614aa2565b604080518881526020810188905290810182905273ffffffffffffffffffffffffffffffffffffffff89811660608301528a16907ff400e72e69ef4402819dfc57eeddc66f5eb69bf405e0e8098b1946ec1ac14a229060800160405180910390a2505050505050505050565b606082600161445782826000614aa2565b60045467ffffffffffffffff8111156144725761447261570a565b60405190808252806020026020018201604052801561449b578160200160208202803683370190505b50925060005b6004548110156147455773ffffffffffffffffffffffffffffffffffffffff86166000908152601b6020908152604080832084845290915290205484518590839081106144f0576144f0615739565b602002602001018181525050600084828151811061451057614510615739565b6020026020010151111561473d5773ffffffffffffffffffffffffffffffffffffffff86166000908152601b60209081526040808320848452909152812055600480548290811061456357614563615739565b9060005260206000200160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a9059cbb868684815181106145bc576145bc615739565b60200260200101516040518363ffffffff1660e01b815260040161460292919073ffffffffffffffffffffffffffffffffffffffff929092168252602082015260400190565b6020604051808303816000875af1158015614621573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906146459190615892565b5083818151811061465857614658615739565b60200260200101516018828154811061467357614673615739565b90600052602060002001600082825461468c919061587f565b925050819055508573ffffffffffffffffffffffffffffffffffffffff167f1d2f2ca53af5d2f333bd32fdd45f9c52ad8ebe31414f7792912077fcb3876dff8583815181106146dd576146dd615739565b6020026020010151600484815481106146f8576146f8615739565b600091825260209182902001546040805193845273ffffffffffffffffffffffffffffffffffffffff9182169284019290925289169082015260600160405180910390a25b6001016144a1565b50505073ffffffffffffffffffffffffffffffffffffffff9092166000908152601d602052604090204290555090565b808061478d575060265465010000000000900460ff16155b156147a25761479c8484614446565b506147af565b6147af8460016000614aa2565b6000806147bc8685614bfd565b81519193509150841461482b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f5374616b65206e6f7420666f756e6400000000000000000000000000000000006044820152606401610e43565b81606001514210158061484b575060265460ff6101009091041615156001145b8061486a57503360009081526024602052604090205460ff1615156001145b6148d0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f5374616b65206973207374696c6c206c6f636b656421000000000000000000006044820152606401610e43565b60408201518015614a9957601e546148e89082613e3e565b601e5573ffffffffffffffffffffffffffffffffffffffff8716600090815260208052604090205461491a9082613e3e565b73ffffffffffffffffffffffffffffffffffffffff881660009081526020808052604080832093909355602390522080548390811061495b5761495b615739565b9060005260206000209060050201600080820160009055600182016000905560028201600090556003820160009055600482016000905550506149a087600180614aa2565b6006546040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8881166004830152602482018490529091169063a9059cbb906044016020604051808303816000875af1158015614a19573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614a3d9190615892565b50604080518281526020810187905273ffffffffffffffffffffffffffffffffffffffff888116828401529151918916917f1d9308f6b22a2754a1c622bb30889e8f8f956c83e524d039e9d65d5f052eb9089181900360600190a25b50505050505050565b8115614ab057614ab0613da8565b8015614ae657614abf83611707565b73ffffffffffffffffffffffffffffffffffffffff84166000908152601260205260409020555b73ffffffffffffffffffffffffffffffffffffffff831615614bf8576000806000614b10866127ee565b925092509250614b1f8661538e565b73ffffffffffffffffffffffffffffffffffffffff86166000908152601260205260409020829055828110614ba3576000614b5a8285613e3e565b601f54909150614b6a9082613f81565b601f55614b778482613f81565b73ffffffffffffffffffffffffffffffffffffffff881660009081526021602052604090205550614bf4565b6000614baf8483613e3e565b601f54909150614bbf9082613e3e565b601f55614bcc8482613e3e565b73ffffffffffffffffffffffffffffffffffffffff8816600090815260216020526040902055505b5050505b505050565b614c326040518060a0016040528060008019168152602001600081526020016000815260200160008152602001600081525090565b6000805b73ffffffffffffffffffffffffffffffffffffffff8516600090815260236020526040902054811015614d465773ffffffffffffffffffffffffffffffffffffffff85166000908152602360205260409020805482908110614c9a57614c9a615739565b9060005260206000209060050201600001548403614d3e5773ffffffffffffffffffffffffffffffffffffffff85166000908152602360205260409020805482908110614ce957614ce9615739565b90600052602060002090600502016040518060a0016040529081600082015481526020016001820154815260200160028201548152602001600382015481526020016004820154815250509250809150614d46565b600101614c36565b5081518314614db1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f5374616b65206e6f7420666f756e6400000000000000000000000000000000006044820152606401610e43565b9250929050565b6040805173ffffffffffffffffffffffffffffffffffffffff85811660248301528481166044830152606480830185905283518084039091018152608490920183526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f23b872dd000000000000000000000000000000000000000000000000000000001790529151600092839290881691614e579190615919565b6000604051808303816000865af19150503d8060008114614e94576040519150601f19603f3d011682016040523d82523d6000602084013e614e99565b606091505b5091509150818015614ec3575080511580614ec3575080806020019051810190614ec39190615892565b614bf4576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f5472616e7366657248656c7065723a205452414e534645525f46524f4d5f464160448201527f494c4544000000000000000000000000000000000000000000000000000000006064820152608401610e43565b6000614f5c42600b54613ffa565b905090565b601654601c54614f72904290613e3e565b106150b25760075473ffffffffffffffffffffffffffffffffffffffff161561502a57600760009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16638f73c5ae6040518163ffffffff1660e01b81526004016020604051808303816000875af1158015615004573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061502891906157e9565b505b6006546040517fc00007b000000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff9091169063c00007b090602401600060405180830381600087803b15801561509557600080fd5b505af11580156150a9573d6000803e3d6000fd5b505042601c5550505b60006150d46150cc600c5442613e3e90919063ffffffff16565b601654613ffa565b905060006150e0613441565b905060005b600454811015614bf85760006004828154811061510457615104615739565b6000918252602090912001546040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff909116906370a0823190602401602060405180830381865afa15801561517b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061519f91906157e9565b90506151b884601384815481106114d8576114d8615739565b601783815481106151cb576151cb615739565b9060005260206000200160008282546151e4919061587f565b925050819055508282815181106151fd576151fd615739565b60200260200101516019838154811061521857615218615739565b906000526020600020018190555060006152756018848154811061523e5761523e615739565b90600052602060002001546017858154811061525c5761525c615739565b9060005260206000200154613e3e90919063ffffffff16565b90508082116152a45760006013848154811061529357615293615739565b6000918252602090912001556152e8565b60006152b08383613e3e565b90506152c760165482613f3f90919063ffffffff16565b601385815481106152da576152da615739565b600091825260209091200155505b50506001016150e5565b60008184841115615330576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610e4391906155f5565b50600061533d848661586c565b95945050505050565b60008183615381576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610e4391906155f5565b50600061533d84866157ae565b73ffffffffffffffffffffffffffffffffffffffff8116156154675760006153b582610bec565b905060005b600454811015614bf8578181815181106153d6576153d6615739565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff85166000908152601b835260408082208583529093529190912055601980548290811061542657615426615739565b600091825260208083209091015473ffffffffffffffffffffffffffffffffffffffff86168352601a825260408084208585529092529120556001016153ba565b50565b73ffffffffffffffffffffffffffffffffffffffff8116811461546757600080fd5b60006020828403121561549e57600080fd5b8135613e808161546a565b6020808252825182820181905260009190848201906040850190845b818110156154e1578351835292840192918401916001016154c5565b50909695505050505050565b6000602082840312156154ff57600080fd5b5035919050565b6000806040838503121561551957600080fd5b50508035926020909101359150565b602080825282518282018190526000919060409081850190868401855b828110156155895781518051855286810151878601528581015186860152606080820151908601526080908101519085015260a09093019290850190600101615545565b5091979650505050505050565b600080600080608085870312156155ac57600080fd5b84356155b78161546a565b966020860135965060408601359560600135945092505050565b60005b838110156155ec5781810151838201526020016155d4565b50506000910152565b60208152600082518060208401526156148160408501602087016155d1565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169190910160400192915050565b60008060006060848603121561565b57600080fd5b505081359360208301359350604090920135919050565b6000806040838503121561568557600080fd5b82356156908161546a565b946020939093013593505050565b801515811461546757600080fd5b600080604083850312156156bf57600080fd5b8235915060208301356156d18161569e565b809150509250929050565b600080604083850312156156ef57600080fd5b82356156fa8161546a565b915060208301356156d18161546a565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b8082028115828204841417610eb957610eb9615768565b6000826157e4577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b6000602082840312156157fb57600080fd5b5051919050565b600181811c9082168061581657607f821691505b602082108103610c96577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b60006020828403121561586157600080fd5b8151613e808161546a565b81810381811115610eb957610eb9615768565b80820180821115610eb957610eb9615768565b6000602082840312156158a457600080fd5b8151613e808161569e565b805169ffffffffffffffffffff81168114610d9f57600080fd5b600080600080600060a086880312156158e157600080fd5b6158ea866158af565b945060208601519350604086015192506060860151915061590d608087016158af565b90509295509295909350565b6000825161592b8184602087016155d1565b919091019291505056fea2646970667358221220e4716ab1889f316057138fe44c637fd8d9c0ea22572601847b8dc238ae47ebc764736f6c63430008170033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000ba079be8f77c8c989cc5a575e8fd010efc8ee48400000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000d2d8beb901f90163be4667a85cddebb7177eb3e300000000000000000000000017fc002b466eec40dae837fc4be5c67993ddbd6f000000000000000000000000e61d9ed1e5dc261d1e90a99304fadcef2c76fd10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000009d2f299715d94d8a7e6f5eaa8e654e8c74a988a700000000000000000000000011cdb42b0eb46d95f990bedd4695a6e3fa034978000000000000000000000000aafcfd42c9954c6689ef1901e03db742520829c5000000000000000000000000912ce59144191c1204e64559fe8253a0e49e6548
-----Decoded View---------------
Arg [0] : _owner (address): 0xBA079bE8f77c8c989cC5A575e8fd010EFc8EE484
Arg [1] : _rewardTokens (address[]): 0x9d2F299715D94d8A7E6F5eaa8E654E8c74a988A7,0x11cDb42B0EB46D95f990BeDD4695A6e3fA034978,0xaAFcFD42c9954C6689ef1901e03db742520829c5,0x912CE59144191C1204E64559FE8253a0e49E6548
Arg [2] : _stakingToken (address): 0xd2D8BEB901f90163bE4667A85cDDEbB7177eb3E3
Arg [3] : _fraxAddress (address): 0x17FC002b466eEc40DaE837Fc4bE5c67993ddBd6F
Arg [4] : _timelockAddress (address): 0xe61D9ed1e5Dc261D1e90a99304fADCef2c76FD10
Arg [5] : _rewarder_address (address): 0x0000000000000000000000000000000000000000
-----Encoded View---------------
11 Constructor Arguments found :
Arg [0] : 000000000000000000000000ba079be8f77c8c989cc5a575e8fd010efc8ee484
Arg [1] : 00000000000000000000000000000000000000000000000000000000000000c0
Arg [2] : 000000000000000000000000d2d8beb901f90163be4667a85cddebb7177eb3e3
Arg [3] : 00000000000000000000000017fc002b466eec40dae837fc4be5c67993ddbd6f
Arg [4] : 000000000000000000000000e61d9ed1e5dc261d1e90a99304fadcef2c76fd10
Arg [5] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [6] : 0000000000000000000000000000000000000000000000000000000000000004
Arg [7] : 0000000000000000000000009d2f299715d94d8a7e6f5eaa8e654e8c74a988a7
Arg [8] : 00000000000000000000000011cdb42b0eb46d95f990bedd4695a6e3fa034978
Arg [9] : 000000000000000000000000aafcfd42c9954c6689ef1901e03db742520829c5
Arg [10] : 000000000000000000000000912ce59144191c1204e64559fe8253a0e49e6548
Deployed Bytecode Sourcemap
159440:472:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;130756:720;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;155781:113;;;;;;:::i;:::-;;:::i;:::-;;115022:222;;;;;;:::i;:::-;;:::i;:::-;;;1393:25:1;;;1381:2;1366:18;115022:222:0;1247:177:1;34855:141:0;;;;;;:::i;:::-;;:::i;149378:242::-;;;:::i;104175:26::-;;;;;;;;;;;;1605:42:1;1593:55;;;1575:74;;1563:2;1548:18;104175:26:0;1429:226:1;139555:163:0;;;;;;:::i;:::-;;:::i;154529:153::-;;;:::i;101111:19::-;;;;;;;;;151151:261;;;;;;:::i;:::-;;:::i;131642:322::-;;;:::i;114714:133::-;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;149964:357::-;;;;;;:::i;:::-;;:::i;108837:44::-;;;;;;;;;;;;;;;3797:14:1;;3790:22;3772:41;;3760:2;3745:18;108837:44:0;3632:187:1;123410:1055:0;;;;;;:::i;:::-;;:::i;108611:35::-;;;;;;;;;;;;114469:127;;;;;;:::i;:::-;114562:26;;114535:7;114562:26;;;:17;:26;;;;;;;114469:127;106033:39;;;;;;108949:25;;;;;;;;;;;;154735:96;;;:::i;144992:210::-;;;:::i;159505:46::-;;;:::i;:::-;;;;;;;:::i;104454:32::-;;;;;;;;;104369:30;;;;;;;;;123075:187;;;;;;:::i;:::-;;:::i;139076:183::-;;;;;;:::i;:::-;139222:10;139197:36;;;;:24;:36;;;;;;;;;:54;;;;;;;;;;139190:61;;;;;;139076:183;34623:29;;;;;;;;;109008:31;;;:::i;115686:6865::-;;;:::i;114248:111::-;114329:22;;114248:111;;105916:55;;;;;;:::i;:::-;;;;;;;;;;;;;;152597:796;;;;;;:::i;:::-;;:::i;107086:29::-;;;;;;105042:32;;;;;;103594:47;;;;;;;;;102767:245;;;;;;:::i;:::-;;:::i;124727:2692::-;;;;;;:::i;:::-;;:::i;107899:53::-;;;;;;:::i;:::-;;:::i;:::-;;;;5706:25:1;;;5762:2;5747:18;;5740:34;;;;5790:18;;;5783:34;;;;5848:2;5833:18;;5826:34;5891:3;5876:19;;5869:35;5693:3;5678:19;107899:53:0;5447:463:1;35004:271:0;;;:::i;155058:126::-;;;:::i;101187:29::-;;;;;;:::i;:::-;;:::i;106464:28::-;;;;;;:::i;:::-;;:::i;151656:553::-;;;;;;:::i;:::-;;:::i;127744:1952::-;;;;;;:::i;:::-;;:::i;:::-;;;;6117:25:1;;;6173:2;6158:18;;6151:34;;;;6201:18;;;6194:34;6105:2;6090:18;127744:1952:0;5915:319:1;34596:20:0;;;;;;;;;142188:229;;;;;;:::i;:::-;;:::i;155547:130::-;;;;;;:::i;:::-;;:::i;108436:26::-;;;;;;;;;;;;108142:76;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;150910:128;;;;;;:::i;:::-;;:::i;154366:97::-;;;:::i;106352:28::-;;;;;;:::i;:::-;;:::i;153607:537::-;;;;;;:::i;:::-;;:::i;135051:1269::-;;;;;;:::i;:::-;;:::i;104913:61::-;;;;;;108716:25;;;;;;;;;;;;155303:116;;;;;;:::i;:::-;;:::i;103018:347::-;;;:::i;104647:29::-;;;;;;129843:704;;;:::i;104766:50::-;;;;;;154887:108;;;:::i;136507:1466::-;;;;;;:::i;:::-;;:::i;122699:157::-;;;;;;:::i;:::-;;:::i;113898:128::-;;;;;;:::i;:::-;113992:26;;113965:7;113992:26;;;:17;:26;;;;;;;113898:128;104091:38;;;;;;;;;113640:113;113722:23;;113640:113;;154216:97;;;:::i;108518:29::-;;;;;;;;;;;;150485:304;;;;;;:::i;:::-;;:::i;104554:27::-;;;;;;108022:47;;;;;;:::i;:::-;;;;;;;;;;;;;;;;138691:226;;;;;;:::i;:::-;;:::i;105418:51::-;;;;;;105209:59;;;;;;105664:28;;;;;;:::i;:::-;;:::i;108323:24::-;;;;;;;;;148874:355;;;:::i;130756:720::-;130877:12;:19;130810:27;;130863:34;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;130863:34:0;-1:-1:-1;130912:26:0;;;;;;;:17;:26;;;;;;130850:47;;-1:-1:-1;130912:31:0;130908:559;;130964:9;130959:103;130983:12;:19;130979:23;;130959:103;;;131045:1;131029:10;131040:1;131029:13;;;;;;;;:::i;:::-;;;;;;;;;;:17;131004:3;;130959:103;;;;130756:720;;;:::o;130908:559::-;131103:36;131142:16;:14;:16::i;:::-;131103:55;;131227:9;131222:234;131246:12;:19;131242:23;;131222:234;;;131420:16;;;;;;;:7;:16;;;;;;;;:19;;;;;;;;;131367:32;;;:23;:32;;;;;:35;;;;;;;;;131340:22;;131308:132;;131420:19;131308:107;;131410:4;;131309:95;;131340:63;;131367:35;131340:19;;131437:1;;131340:22;;;;;;:::i;:::-;;;;;;;:26;;:63;;;;:::i;:::-;131309:26;;;;;;;:17;:26;;;;;;;:30;:95::i;:::-;131308:101;;:107::i;:::-;:111;;:132::i;:::-;131292:10;131303:1;131292:13;;;;;;;;:::i;:::-;;;;;;;;;;:148;131267:3;;131222:234;;;;131088:379;130908:559;130756:720;;;:::o;155781:113::-;109861:5;;;;109847:10;:19;;:52;;-1:-1:-1;109884:15:0;;;;109870:10;:29;109847:52;109839:86;;;;;;;8664:2:1;109839:86:0;;;8646:21:1;8703:2;8683:18;;;8676:30;8742:23;8722:18;;;8715:51;8783:18;;109839:86:0;;;;;;;;;155856:5:::1;:30:::0;;;::::1;;::::0;;;::::1;::::0;;;::::1;::::0;;155781:113::o;115022:222::-;115131:19;;115196:28;;115081:7;;115108:127;;115166:26;115131:19;115166:4;:26;:::i;:::-;115165:59;;;;:::i;:::-;115108:8;:127::i;:::-;115101:134;115022:222;-1:-1:-1;;115022:222:0:o;34855:141::-;35335:5;;;;35321:10;:19;35313:79;;;;;;;9655:2:1;35313:79:0;;;9637:21:1;9694:2;9674:18;;;9667:30;9733:34;9713:18;;;9706:62;9804:17;9784:18;;;9777:45;9839:19;;35313:79:0;9453:411:1;35313:79:0;34927:14:::1;:23:::0;;;::::1;;::::0;::::1;::::0;;::::1;::::0;;;34966:22:::1;::::0;1575:74:1;;;34966:22:0::1;::::0;1563:2:1;1548:18;34966:22:0::1;;;;;;;34855:141:::0;:::o;149378:242::-;110089:5;;;;110075:10;:19;;:52;;-1:-1:-1;110112:15:0;;;;110098:10;:29;110075:52;:87;;;-1:-1:-1;110145:17:0;;;;110131:10;:31;110075:87;110067:122;;;;;;;10071:2:1;110067:122:0;;;10053:21:1;10110:2;10090:18;;;10083:30;10149:24;10129:18;;;10122:52;10191:18;;110067:122:0;9869:346:1;110067:122:0;149454:13:::1;::::0;;;::::1;;;149453:14;149445:46;;;::::0;::::1;::::0;;10422:2:1;149445:46:0::1;::::0;::::1;10404:21:1::0;10461:2;10441:18;;;10434:30;10500:21;10480:18;;;10473:49;10539:18;;149445:46:0::1;10220:343:1::0;149445:46:0::1;149502:13;:20:::0;;;::::1;::::0;::::1;::::0;;149565:6:::1;:4;:6::i;:::-;149589:23;::::0;::::1;::::0;;;::::1;149378:242::o:0;139555:163::-;38872:1;39478:7;;:19;39470:63;;;;;;;10770:2:1;39470:63:0;;;10752:21:1;10809:2;10789:18;;;10782:30;10848:33;10828:18;;;10821:61;10899:18;;39470:63:0;10568:355:1;39470:63:0;38872:1;39611:18;;139640:70:::1;139653:10;::::0;139677:9;139688:4;139694:15:::1;139640:12;:70::i;:::-;-1:-1:-1::0;;38828:1:0;39790:7;:22;139555:163::o;154529:153::-;109861:5;;;;109847:10;:19;;:52;;-1:-1:-1;109884:15:0;;;;109870:10;:29;109847:52;109839:86;;;;;;;8664:2:1;109839:86:0;;;8646:21:1;8703:2;8683:18;;;8676:30;8742:23;8722:18;;;8715:51;8783:18;;109839:86:0;8462:345:1;109839:86:0;154642:32:::1;::::0;;154606:68;;::::1;154642:32:::0;;;;::::1;;;154641:33;154606:68:::0;;::::1;;::::0;;154529:153::o;151151:261::-;109861:5;;;;109847:10;:19;;:52;;-1:-1:-1;109884:15:0;;;;109870:10;:29;109847:52;109839:86;;;;;;;8664:2:1;109839:86:0;;;8646:21:1;8703:2;8683:18;;;8676:30;8742:23;8722:18;;;8715:51;8783:18;;109839:86:0;8462:345:1;109839:86:0;151242:33:::1;::::0;::::1;;::::0;;;:15:::1;:33;::::0;;;;;::::1;;:41;;:33:::0;:41:::1;151234:73;;;::::0;::::1;::::0;;11130:2:1;151234:73:0::1;::::0;::::1;11112:21:1::0;11169:2;11149:18;;;11142:30;11208:21;11188:18;;;11181:49;11247:18;;151234:73:0::1;10928:343:1::0;151234:73:0::1;151371:33;;;::::0;;;:15:::1;:33;::::0;;;;151364:40;;;::::1;::::0;;151151:261::o;131642:322::-;131786:12;:19;131697:38;;131772:34;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;131772:34:0;;131748:58;;131822:9;131817:140;131841:12;:19;131837:23;;131817:140;;;131910:35;131929:15;;131910:11;131922:1;131910:14;;;;;;;;:::i;:::-;;;;;;;;;:18;;:35;;;;:::i;:::-;131883:21;131905:1;131883:24;;;;;;;;:::i;:::-;;;;;;;;;;:62;131862:3;;131817:140;;;;131642:322;:::o;114714:133::-;114818:21;;;;;;;:12;:21;;;;;;;;114811:28;;;;;;;;;;;;;;;;;114778:20;;114811:28;;114818:21;;114811:28;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;114714:133;;;:::o;149964:357::-;110299:12;;;;:20;;:12;:20;110291:49;;;;;;;11478:2:1;110291:49:0;;;11460:21:1;11517:2;11497:18;;;11490:30;11556:18;11536;;;11529:46;11592:18;;110291:49:0;11276:340:1;110291:49:0;150117:40:::1;::::0;::::1;;::::0;;;:24:::1;:40;::::0;;;;;;;150158:10:::1;150117:52:::0;;;;;;;;::::1;;:83:::0;::::1;;;-1:-1:-1::0;150189:10:0::1;150173:27;::::0;;;:15:::1;:27;::::0;;;;;::::1;;150117:83;150109:122;;;::::0;::::1;::::0;;11823:2:1;150109:122:0::1;::::0;::::1;11805:21:1::0;11862:2;11842:18;;;11835:30;11901:28;11881:18;;;11874:56;11947:18;;150109:122:0::1;11621:350:1::0;150109:122:0::1;150242:71;150255:14;150271:10;150283:6;150291:4;150297:15;150242:12;:71::i;:::-;149964:357:::0;;;;:::o;123410:1055::-;123505:5;;123473:7;;123497:28;123505:5;123497:28;123493:964;;123703:34;123740:28;123760:7;123740:19;:28::i;:::-;123703:65;-1:-1:-1;123787:30:0;;123783:570;;123869:5;;:24;;;;;:5;1593:55:1;;;123869:24:0;;;1575:74:1;123838:27:0;;123868:84;;123925:26;;123868:52;;104311:4;;123869:5;;;:15;;1548:18:1;;123869:24:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;123868:30;;:52::i;:84::-;123838:114;;123989:24;124016:75;104311:4;124017:47;124043:20;;124018:19;124017:25;;:47;;;;:::i;124016:75::-;123989:102;;124197:20;;124178:16;:39;124174:84;;;-1:-1:-1;124238:20:0;;124174:84;124286:16;123410:1055;-1:-1:-1;;;;123410:1055:0:o;123783:570::-;-1:-1:-1;124352:1:0;;123410:1055;-1:-1:-1;;123410:1055:0:o;123493:964::-;-1:-1:-1;124456:1:0;;123410:1055;-1:-1:-1;123410:1055:0:o;154735:96::-;109861:5;;;;109847:10;:19;;:52;;-1:-1:-1;109884:15:0;;;;109870:10;:29;109847:52;109839:86;;;;;;;8664:2:1;109839:86:0;;;8646:21:1;8703:2;8683:18;;;8676:30;8742:23;8722:18;;;8715:51;8783:18;;109839:86:0;8462:345:1;109839:86:0;154810:13:::1;::::0;;154793:30;;::::1;154810:13:::0;;;;::::1;;;154809:14;154793:30:::0;;::::1;;::::0;;154735:96::o;144992:210::-;145044:16;38872:1;39478:7;;:19;39470:63;;;;;;;10770:2:1;39470:63:0;;;10752:21:1;10809:2;10789:18;;;10782:30;10848:33;10828:18;;;10821:61;10899:18;;39470:63:0;10568:355:1;39470:63:0;38872:1;39611:18;;145081:23:::1;::::0;;;::::1;;;:32;145073:69;;;::::0;::::1;::::0;;12367:2:1;145073:69:0::1;::::0;::::1;12349:21:1::0;12406:2;12386:18;;;12379:30;12445:27;12425:18;;;12418:55;12490:18;;145073:69:0::1;12165:349:1::0;145073:69:0::1;145160:34;145171:10;145183;145160;:34::i;:::-;145153:41;;38828:1:::0;39790:7;:22;144992:210;:::o;159505:46::-;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;123075:187::-;123142:7;123169:85;104311:4;123169:59;123199:28;;123170:23;123185:7;123170:14;:23::i;109008:31::-;;;;;;;:::i;115686:6865::-;115733:7;115814:25;117508:31;117568:12;;;;;;;;;;;:23;;;:25;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;117508:86;;117609:25;117658:5;:14;;;:16;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;117835:75;;;;;1605:42:1;1593:55;;117835:75:0;;;1575:74:1;117609:66:0;;-1:-1:-1;117810:22:0;;117842:42;;117835:60;;1548:18:1;;117835:75:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;117810:100;;117925:32;118012:4;:16;;;:18;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;117986:21;:19;:21::i;:::-;117961:47;;:14;:47;:::i;:::-;117960:70;;;;:::i;:::-;117925:105;-1:-1:-1;118065:33:0;117925:105;118093:4;118065:33;:::i;:::-;118045:53;115686:6865;-1:-1:-1;;;;;;115686:6865:0:o;152597:796::-;109861:5;;;;109847:10;:19;;:52;;-1:-1:-1;109884:15:0;;;;109870:10;:29;109847:52;109839:86;;;;;;;8664:2:1;109839:86:0;;;8646:21:1;8703:2;8683:18;;;8676:30;8742:23;8722:18;;;8715:51;8783:18;;109839:86:0;8462:345:1;109839:86:0;104311:4:::1;152762:20;:44;;152754:93;;;::::0;::::1;::::0;;13419:2:1;152754:93:0::1;::::0;::::1;13401:21:1::0;13458:2;13438:18;;;13431:30;13497:34;13477:18;;;13470:62;13568:6;13548:18;;;13541:34;13592:19;;152754:93:0::1;13217:400:1::0;152754:93:0::1;152970:1;152938:29;:33;152930:72;;;::::0;::::1;::::0;;14175:2:1;152930:72:0::1;::::0;::::1;14157:21:1::0;14214:2;14194:18;;;14187:30;14253:28;14233:18;;;14226:56;14299:18;;152930:72:0::1;13973:350:1::0;152930:72:0::1;153015:19;:42:::0;;;153068:20:::1;:44:::0;;;153123:28:::1;:60:::0;;;153201:40:::1;::::0;1393:25:1;;;153201:40:0::1;::::0;1381:2:1;1366:18;153201:40:0::1;;;;;;;153257:52;153289:19;;153257:52;;;;1393:25:1::0;;1381:2;1366:18;;1247:177;153257:52:0::1;;;;;;;;153325:60;153356:28;;153325:60;;;;1393:25:1::0;;1381:2;1366:18;;1247:177;153325:60:0::1;;;;;;;;152597:796:::0;;;:::o;102767:245::-;109861:5;;;;109847:10;:19;;:52;;-1:-1:-1;109884:15:0;;;;109870:10;:29;109847:52;109839:86;;;;;;;8664:2:1;109839:86:0;;;8646:21:1;8703:2;8683:18;;;8676:30;8742:23;8722:18;;;8715:51;8783:18;;109839:86:0;8462:345:1;109839:86:0;102864:37:::1;::::0;::::1;102856:71;;;::::0;::::1;::::0;;14530:2:1;102856:71:0::1;::::0;::::1;14512:21:1::0;14569:2;14549:18;;;14542:30;14608:23;14588:18;;;14581:51;14649:18;;102856:71:0::1;14328:345:1::0;102856:71:0::1;102940:15;:64:::0;;;::::1;;::::0;;;::::1;::::0;;;::::1;::::0;;102767:245::o;124727:2692::-;124918:21;;;124816:32;124918:21;;;:12;:21;;;;;:32;;124816;;124918:21;124940:9;;124918:32;;;;;;:::i;:::-;;;;;;;;;124887:63;;;;;;;;124918:32;;;;;;;124887:63;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;125133:28;;;;;:19;:28;;;;;;124887:63;;-1:-1:-1;;125129:224:0;;;-1:-1:-1;125226:25:0;;;;125129:224;;;-1:-1:-1;125313:28:0;;;;;;;:19;:28;;;;;;125129:224;125442:15;125412:9;:26;;;:45;125408:1802;;125637:26;;;;125606:28;;;;;;;:19;:28;;;;;;:57;125602:1087;;;125683:26;125741:17;125712:9;:26;;;:46;;;;:::i;:::-;125683:75;;125777:25;125823:9;:26;;;125805:15;:44;;;;:::i;:::-;125777:72;-1:-1:-1;125929:33:0;125965:38;125980:22;126001:1;125980:18;:22;:::i;125965:38::-;125929:74;-1:-1:-1;126220:17:0;126292:21;126296:17;126220;126292:21;:::i;:::-;126241:46;126269:18;126241:25;:46;:::i;:::-;126240:74;;;;:::i;:::-;126220:94;-1:-1:-1;126373:38:0;126394:17;126373:18;:38;:::i;:::-;126360:52;;:9;:52;:::i;:::-;126333:79;;125664:764;;;;125408:1802;;125602:1087;126672:1;126645:28;;125408:1802;;;126834:21;126889:20;126941:17;126912:9;:26;;;:46;;;;:::i;:::-;126889:69;;126977:20;127029:15;127000:9;:26;;;:44;;;;:::i;:::-;126977:67;-1:-1:-1;127111:1:0;127080:27;126977:67;127080:12;:27;:::i;:::-;127079:33;;;;:::i;:::-;127063:49;;126870:258;;127169:29;127184:13;127169:14;:29::i;:::-;127142:56;;126754:456;125408:1802;127332:9;:25;;;127305:24;:52;127301:110;;;127386:9;:25;;;127359:52;;127301:110;124850:2569;;124727:2692;;;;:::o;107899:53::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;107899:53:0;;-1:-1:-1;107899:53:0;;;:::o;35004:271::-;35073:14;;;;35059:10;:28;35051:94;;;;;;;15143:2:1;35051:94:0;;;15125:21:1;15182:2;15162:18;;;15155:30;15221:34;15201:18;;;15194:62;15292:23;15272:18;;;15265:51;15333:19;;35051:94:0;14941:417:1;35051:94:0;35174:5;;;35181:14;35161:35;;;35174:5;;;;15598:34:1;;35181:14:0;;;;15663:2:1;15648:18;;15641:43;35161:35:0;;15510:18:1;35161:35:0;;;;;;;35215:14;;;;35207:22;;;;;;35215:14;;;35207:22;;;;35240:27;;;35004:271::o;155058:126::-;109861:5;;;;109847:10;:19;;:52;;-1:-1:-1;109884:15:0;;;;109870:10;:29;109847:52;109839:86;;;;;;;8664:2:1;109839:86:0;;;8646:21:1;8703:2;8683:18;;;8676:30;8742:23;8722:18;;;8715:51;8783:18;;109839:86:0;8462:345:1;109839:86:0;155153:23:::1;::::0;;155126:50;;::::1;155153:23:::0;;;;::::1;;;155152:24;155126:50:::0;;::::1;;::::0;;155058:126::o;101187:29::-;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;101187:29:0;:::o;106464:28::-;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;106464:28:0;:::o;151656:553::-;109861:5;;;;109847:10;:19;;:52;;-1:-1:-1;109884:15:0;;;;109870:10;:29;109847:52;109839:86;;;;;;;8664:2:1;109839:86:0;;;8646:21:1;8703:2;8683:18;;;8676:30;8742:23;8722:18;;;8715:51;8783:18;;109839:86:0;8462:345:1;109839:86:0;151855:12:::1;::::0;::::1;;151851:164;;151915:12;::::0;::::1;::::0;;::::1;151891:37:::0;;::::1;::::0;151883:66:::1;;;::::0;::::1;::::0;;11478:2:1;151883:66:0::1;::::0;::::1;11460:21:1::0;11517:2;11497:18;;;11490:30;11556:18;11536;;;11529:46;11592:18;;151883:66:0::1;11276:340:1::0;151883:66:0::1;152130:5;::::0;152101:48:::1;::::0;;;;:28:::1;152130:5:::0;;::::1;152101:48;::::0;::::1;15869:74:1::0;15959:18;;;15952:34;;;152101:28:0;;::::1;::::0;::::1;::::0;15842:18:1;;152101:48:0::1;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1::0;152165:36:0::1;::::0;;15899:42:1;15887:55;;15869:74;;15974:2;15959:18;;15952:34;;;152165:36:0::1;::::0;15842:18:1;152165:36:0::1;;;;;;;;151656:553:::0;;:::o;127744:1952::-;128038:26;;;127836:27;128038:26;;;:17;:26;;;;;;;127836:27;128225:24;128056:7;128225:15;:24::i;:::-;128325:26;;;128262:33;128325:26;;;:17;:26;;;;;;128202:47;;-1:-1:-1;128262:33:0;128325:31;:66;;;;-1:-1:-1;128360:26:0;;;;;;;:17;:26;;;;;;:31;128325:66;128324:143;;;-1:-1:-1;128435:31:0;;;;;;;:22;:31;;;;;;128411:55;;;128324:143;128306:638;;;-1:-1:-1;128708:20:0;128306:638;;;128896:31;;;;;;;:22;:31;;;;;;128931:1;;128873:54;;:20;:54;:::i;:::-;128872:60;;;;:::i;:::-;128844:88;;128306:638;129079:1;129057:23;;129096:9;129091:598;129115:21;;;;;;;:12;:21;;;;;:28;129111:32;;129091:598;;;129196:21;;;129165:28;129196:21;;;:12;:21;;;;;:24;;129218:1;;129196:24;;;;;;:::i;:::-;;;;;;;;;;;129165:55;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;129292:32;129327:34;129350:7;129359:1;129327:22;:34::i;:::-;129443:19;;;;129292:69;;-1:-1:-1;129423:17:0;104311:4;129538:52;129565:25;129292:69;129538:52;:::i;:::-;129525:66;;:9;:66;:::i;:::-;129524:91;;;;:::i;:::-;129511:105;;:9;:105;:::i;:::-;129477:139;-1:-1:-1;129631:46:0;129477:139;129631:46;;:::i;:::-;;-1:-1:-1;;129145:3:0;;;;;-1:-1:-1;129091:598:0;;-1:-1:-1;;129091:598:0;;;127965:1731;127744:1952;;;;;:::o;142188:229::-;38872:1;39478:7;;:19;39470:63;;;;;;;10770:2:1;39470:63:0;;;10752:21:1;10809:2;10789:18;;;10782:30;10848:33;10828:18;;;10821:61;10899:18;;39470:63:0;10568:355:1;39470:63:0;38872:1;39611:18;;142287:17:::1;::::0;;;::::1;;;:26;142279:57;;;::::0;::::1;::::0;;16449:2:1;142279:57:0::1;::::0;::::1;16431:21:1::0;16488:2;16468:18;;;16461:30;16527:20;16507:18;;;16500:48;16565:18;;142279:57:0::1;16247:342:1::0;142279:57:0::1;142347:62;142363:10;142375;142387:6;142395:13;142347:15;:62::i;155547:130::-:0;109861:5;;;;109847:10;:19;;:52;;-1:-1:-1;109884:15:0;;;;109870:10;:29;109847:52;109839:86;;;;;;;8664:2:1;109839:86:0;;;8646:21:1;8703:2;8683:18;;;8676:30;8742:23;8722:18;;;8715:51;8783:18;;109839:86:0;8462:345:1;109839:86:0;155631:17:::1;:38:::0;;;::::1;;::::0;;;::::1;::::0;;;::::1;::::0;;155547:130::o;150910:128::-;109861:5;;;;109847:10;:19;;:52;;-1:-1:-1;109884:15:0;;;;109870:10;:29;109847:52;109839:86;;;;;;;8664:2:1;109839:86:0;;;8646:21:1;8703:2;8683:18;;;8676:30;8742:23;8722:18;;;8715:51;8783:18;;109839:86:0;8462:345:1;109839:86:0;150990:33:::1;;;::::0;;;:15:::1;:33;::::0;;;;:40;;;::::1;151026:4;150990:40;::::0;;150910:128::o;154366:97::-;109861:5;;;;109847:10;:19;;:52;;-1:-1:-1;109884:15:0;;;;109870:10;:29;109847:52;109839:86;;;;;;;8664:2:1;109839:86:0;;;8646:21:1;8703:2;8683:18;;;8676:30;8742:23;8722:18;;;8715:51;8783:18;;109839:86:0;8462:345:1;109839:86:0;154443:12:::1;::::0;;154427:28;;::::1;154443:12;::::0;;::::1;154442:13;154427:28;::::0;;154366:97::o;106352:28::-;;;;;;;;;;;;153607:537;109861:5;;;;109847:10;:19;;:52;;-1:-1:-1;109884:15:0;;;;109870:10;:29;109847:52;109839:86;;;;;;;8664:2:1;109839:86:0;;;8646:21:1;8703:2;8683:18;;;8676:30;8742:23;8722:18;;;8715:51;8783:18;;109839:86:0;8462:345:1;109839:86:0;153794:1:::1;153761:29;:34;;153753:72;;;::::0;::::1;::::0;;16796:2:1;153753:72:0::1;::::0;::::1;16778:21:1::0;16835:2;16815:18;;;16808:30;16874:27;16854:18;;;16847:55;16919:18;;153753:72:0::1;16594:349:1::0;153753:72:0::1;153862:1;153844:14;:19;;153836:57;;;::::0;::::1;::::0;;17150:2:1;153836:57:0::1;::::0;::::1;17132:21:1::0;17189:2;17169:18;;;17162:30;17228:27;17208:18;;;17201:55;17273:18;;153836:57:0::1;16948:349:1::0;153836:57:0::1;153906:28;:60:::0;;;153977:13:::1;:30:::0;;;154025:61:::1;::::0;1393:25:1;;;154025:61:0::1;::::0;1381:2:1;1366:18;154025:61:0::1;;;;;;;154102:34;::::0;1393:25:1;;;154102:34:0::1;::::0;1381:2:1;1366:18;154102:34:0::1;1247:177:1::0;135051:1269:0;38872:1;39478:7;;:19;39470:63;;;;;;;10770:2:1;39470:63:0;;;10752:21:1;10809:2;10789:18;;;10782:30;10848:33;10828:18;;;10821:61;10899:18;;39470:63:0;10568:355:1;39470:63:0;38872:1;39611:18;;135145:10:::1;135157:4;110650:49;135145:10:::0;135157:4;110693:5:::1;110650:23;:49::i;:::-;135233:13:::2;::::0;;;::::2;;;135232:14;135224:41;;;::::0;::::2;::::0;;17504:2:1;135224:41:0::2;::::0;::::2;17486:21:1::0;17543:2;17523:18;;;17516:30;17582:16;17562:18;;;17555:44;17616:18;;135224:41:0::2;17302:338:1::0;135224:41:0::2;135327:28;135357:21:::0;135382:29:::2;135392:10;135404:6;135382:9;:29::i;:::-;135326:85;;;;135461:15;135501:8;135479:9;:19;;;:30;;;;:::i;:::-;135461:48:::0;-1:-1:-1;135679:12:0::2;::::0;135639:91:::2;::::0;135679:12:::2;;135694:10;135714:4;135721:8:::0;135639:31:::2;:91::i;:::-;135814:186;::::0;;::::2;::::0;::::2;::::0;;;;;::::2;135861:25:::0;;::::2;::::0;135814:186;;::::2;::::0;;;;;;;;135923:26;;::::2;::::0;135814:186;;;;;135964:25;;::::2;::::0;135814:186;;;;135785:10:::2;-1:-1:-1::0;135772:24:0;;;:12:::2;:24:::0;;;;;;;:39;;135797:13;;135772:39;::::2;;;;;:::i;:::-;;;;;;;;;;;:228;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;136071:8;136044:23;;:35;;;;;;;:::i;:::-;::::0;;;-1:-1:-1;;136108:10:0::2;136090:29;::::0;;;:17:::2;:29:::0;;;;;:41;;136123:8;;136090:29;:41:::2;::::0;136123:8;;136090:41:::2;:::i;:::-;::::0;;;-1:-1:-1;136200:48:0::2;::::0;-1:-1:-1;136224:10:0::2;136236:5;136243:4;136200:23;:48::i;:::-;136266:46;::::0;;18163:25:1;;;18219:2;18204:18;;18197:34;;;136283:10:0::2;::::0;136266:46:::2;::::0;18136:18:1;136266:46:0::2;;;;;;;-1:-1:-1::0;;38828:1:0;39790:7;:22;-1:-1:-1;;;;;135051:1269:0:o;155303:116::-;109861:5;;;;109847:10;:19;;:52;;-1:-1:-1;109884:15:0;;;;109870:10;:29;109847:52;109839:86;;;;;;;8664:2:1;109839:86:0;;;8646:21:1;8703:2;8683:18;;;8676:30;8742:23;8722:18;;;8715:51;8783:18;;109839:86:0;8462:345:1;109839:86:0;155380:15:::1;:31:::0;;;::::1;;::::0;;;::::1;::::0;;;::::1;::::0;;155303:116::o;103018:347::-;103070:3;103113:14;103129:9;103142:17;103161:22;103187:15;;;;;;;;;;;:31;;;:33;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;103112:108;;;;;;;;;103248:1;103239:5;:10;;:27;;;;-1:-1:-1;103253:13:0;;;103239:27;:57;;;;;103289:7;103270:26;;:15;:26;;;;103239:57;103231:93;;;;;;;19106:2:1;103231:93:0;;;19088:21:1;19145:2;19125:18;;;19118:30;19184:25;19164:18;;;19157:53;19227:18;;103231:93:0;18904:347:1;103231:93:0;-1:-1:-1;103352:5:0;;103018:347;-1:-1:-1;;;103018:347:0:o;129843:704::-;129987:12;:19;129890:42;;129973:34;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;129973:34:0;;129945:62;;130022:23;;130049:1;130022:28;:59;;;-1:-1:-1;130054:22:0;;:27;130022:59;130018:520;;;130126:21;130098:49;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;129843:704;:::o;130018:520::-;130241:9;130236:291;130260:12;:19;130256:23;;130236:291;;;130337:174;130388:104;130469:22;;130388:76;130459:4;130388:66;130439:11;130451:1;130439:14;;;;;;;;:::i;:::-;;;;;;;;;130388:46;130419:14;;130388:26;:24;:26::i;:::-;:30;;:46::i;:104::-;130337:21;130359:1;130337:24;;;;;;;;:::i;:::-;;;;;;;;;:28;;:174;;;;:::i;:::-;130306:25;130332:1;130306:28;;;;;;;;:::i;:::-;;;;;;;;;;:205;130281:3;;130236:291;;154887:108;109861:5;;;;109847:10;:19;;:52;;-1:-1:-1;109884:15:0;;;;109870:10;:29;109847:52;109839:86;;;;;;;8664:2:1;109839:86:0;;;8646:21:1;8703:2;8683:18;;;8676:30;8742:23;8722:18;;;8715:51;8783:18;;109839:86:0;8462:345:1;109839:86:0;154970:17:::1;::::0;;154949:38;;::::1;154970:17:::0;;;;::::1;;;154969:18;154949:38:::0;;::::1;;::::0;;154887:108::o;136507:1466::-;38872:1;39478:7;;:19;39470:63;;;;;;;10770:2:1;39470:63:0;;;10752:21:1;10809:2;10789:18;;;10782:30;10848:33;10828:18;;;10821:61;10899:18;;39470:63:0;10568:355:1;39470:63:0;38872:1;39611:18;;136602:10:::1;136614:4;110650:49;136602:10:::0;136614:4;110693:5:::1;110650:23;:49::i;:::-;136690:13:::2;::::0;;;::::2;;;136689:14;136681:41;;;::::0;::::2;::::0;;17504:2:1;136681:41:0::2;::::0;::::2;17486:21:1::0;17543:2;17523:18;;;17516:30;17582:16;17562:18;;;17555:44;17616:18;;136681:41:0::2;17302:338:1::0;136681:41:0::2;136784:28;136814:21:::0;136839:29:::2;136849:10;136861:6;136839:9;:29::i;:::-;136783:85;;;;136923:15;136907:13;:31;136899:65;;;::::0;::::2;::::0;;19458:2:1;136899:65:0::2;::::0;::::2;19440:21:1::0;19497:2;19477:18;;;19470:30;19536:23;19516:18;;;19509:51;19577:18;;136899:65:0::2;19256:345:1::0;136899:65:0::2;137010:17;137060:15;137031:9;:26;;;:44;137030:97;;137126:1;137030:97;;;137108:15;137079:9;:26;;;:44;;;;:::i;:::-;137010:117:::0;-1:-1:-1;137138:16:0::2;137157:31;137173:15;137157:13:::0;:31:::2;:::i;:::-;137138:50;;137294:9;137283:8;:20;137275:57;;;::::0;::::2;::::0;;19808:2:1;137275:57:0::2;::::0;::::2;19790:21:1::0;19847:2;19827:18;;;19820:30;19886:26;19866:18;;;19859:54;19930:18;;137275:57:0::2;19606:348:1::0;137275:57:0::2;137363:13;;137351:8;:25;;137343:64;;;::::0;::::2;::::0;;20161:2:1;137343:64:0::2;::::0;::::2;20143:21:1::0;20200:2;20180:18;;;20173:30;20239:28;20219:18;;;20212:56;20285:18;;137343:64:0::2;19959:350:1::0;137343:64:0::2;137438:28;;137426:8;:40;;137418:80;;;::::0;::::2;::::0;;20516:2:1;137418:80:0::2;::::0;::::2;20498:21:1::0;20555:2;20535:18;;;20528:30;20594:29;20574:18;;;20567:57;20641:18;;137418:80:0::2;20314:351:1::0;137418:80:0::2;137582:174;;;;;;;;137608:6;137582:174;;;;137629:15;137582:174;;;;137659:9;:19;;;137582:174;;;;137693:13;137582:174;;;;137721:24;137736:8;137721:14;:24::i;:::-;137582:174:::0;;137553:10:::2;137540:24;::::0;;;:12:::2;:24;::::0;;;;:39;;137565:13;;137540:39;::::2;;;;;:::i;:::-;;;;;;;;;;;:216;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;137825:48;137849:10;137861:5;137868:4;137825:23;:48::i;:::-;137891:74;::::0;;20901:25:1;;;20957:2;20942:18;;20935:34;;;137934:15:0::2;20985:18:1::0;;;20978:34;21043:2;21028:18;;21021:34;;;137891:74:0;;137904:10:::2;::::0;137891:74:::2;::::0;;;;;20888:3:1;137891:74:0;;::::2;-1:-1:-1::0;;38828:1:0;39790:7;:22;-1:-1:-1;;;;;;136507:1466:0:o;122699:157::-;122811:26;;;122761:7;122811:26;;;:17;:26;;;;;;122788:60;;122843:4;;122788:50;;122789:16;:14;:16::i;154216:97::-;109861:5;;;;109847:10;:19;;:52;;-1:-1:-1;109884:15:0;;;;109870:10;:29;109847:52;109839:86;;;;;;;8664:2:1;109839:86:0;;;8646:21:1;8703:2;8683:18;;;8676:30;8742:23;8722:18;;;8715:51;8783:18;;109839:86:0;8462:345:1;109839:86:0;154291:14:::1;::::0;;154273:32;;::::1;154291:14;::::0;;;::::1;;;154290:15;154273:32:::0;;::::1;;::::0;;154216:97::o;150485:304::-;110299:12;;;;:20;;:12;:20;110291:49;;;;;;;11478:2:1;110291:49:0;;;11460:21:1;11517:2;11497:18;;;11490:30;11556:18;11536;;;11529:46;11592:18;;110291:49:0;11276:340:1;110291:49:0;150599:40:::1;::::0;::::1;;::::0;;;:24:::1;:40;::::0;;;;;;;150640:10:::1;150599:52:::0;;;;;;;;::::1;;:83:::0;::::1;;;-1:-1:-1::0;150671:10:0::1;150655:27;::::0;;;:15:::1;:27;::::0;;;;;::::1;;150599:83;150591:122;;;::::0;::::1;::::0;;11823:2:1;150591:122:0::1;::::0;::::1;11805:21:1::0;11862:2;11842:18;;;11835:30;11901:28;11881:18;;;11874:56;11947:18;;150591:122:0::1;11621:350:1::0;150591:122:0::1;150724:57;150740:14;150756:10;150768:6;150776:4;150724:15;:57::i;:::-;150485:304:::0;;:::o;138691:226::-;138774:33;;;;;;;:15;:33;;;;;;;;138766:70;;;;;;;21268:2:1;138766:70:0;;;21250:21:1;21307:2;21287:18;;;21280:30;21346:26;21326:18;;;21319:54;21390:18;;138766:70:0;21066:348:1;138766:70:0;138872:10;138847:36;;;;:24;:36;;;;;;;;;:54;;;;;;;;;;:61;;;;138904:4;138847:61;;;138691:226::o;105664:28::-;;;;;;;;;;;;148874:355;148916:13;;;;;;;148908:50;;;;;;;21621:2:1;148908:50:0;;;21603:21:1;21660:2;21640:18;;;21633:30;21699:26;21679:18;;;21672:54;21743:18;;148908:50:0;21419:348:1;148908:50:0;149057:13;:11;:13::i;:::-;149142:15;149125:14;:32;;;149205:15;;149183:38;;149142:15;149183:21;:38::i;:::-;149168:12;:53;148874:355::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;;;;;;;21974:2:1;3824:56:0;;;21956:21:1;22013:2;21993:18;;;21986:30;22052:34;22032:18;;;22025:62;22123:3;22103:18;;;22096:31;22144:19;;3824:56:0;21772: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;;;;;;;22376:2:1;2172:46:0;;;22358:21:1;22415:2;22395:18;;;22388:30;22454:29;22434:18;;;22427:57;22501:18;;2172:46:0;22174: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;140334:1548::-;140549:14;140565:4;110650:49;110674:7;110683:8;110693:5;110650:23;:49::i;:::-;140591:13:::1;::::0;;;::::1;;;140590:14;::::0;:53:::1;;-1:-1:-1::0;140624:10:0::1;140608:27;::::0;;;:15:::1;:27;::::0;;;;;::::1;;:35;;:27:::0;:35:::1;140590:53;140582:96;;;::::0;::::1;::::0;;22732:2:1;140582:96:0::1;::::0;::::1;22714:21:1::0;22771:2;22751:18;;;22744:30;22810:32;22790:18;;;22783:60;22860:18;;140582:96:0::1;22530:354:1::0;140582:96:0::1;140709:1;140697:9;:13;140689:51;;;::::0;::::1;::::0;;23091:2:1;140689:51:0::1;::::0;::::1;23073:21:1::0;23130:2;23110:18;;;23103:30;23169:27;23149:18;;;23142:55;23214:18;;140689:51:0::1;22889:349:1::0;140689:51:0::1;140767:13;;140759:4;:21;;140751:60;;;::::0;::::1;::::0;;20161:2:1;140751:60:0::1;::::0;::::1;20143:21:1::0;20200:2;20180:18;;;20173:30;20239:28;20219:18;;;20212:56;20285:18;;140751:60:0::1;19959:350:1::0;140751:60:0::1;140838:28;;140830:4;:36;;140822:75;;;::::0;::::1;::::0;;20516:2:1;140822:75:0::1;::::0;::::1;20498:21:1::0;20555:2;20535:18;;;20528:30;20594:29;20574:18;;;20567:57;20641:18;;140822:75:0::1;20314:351:1::0;140822:75:0::1;140910:23;140936:20;140951:4;140936:14;:20::i;:::-;141055:33;::::0;::::1;140967:14;141055:33:::0;;;:17:::1;:33:::0;;;;;;;;140994:95;;23489:66:1;23476:2;23472:15;;;23468:88;140994:95:0;;::::1;23456:101:1::0;;;;23573:12;;;23566:28;;;23610:12;;;23603:28;;;23647:12;;;23640:28;140910:46:0;;-1:-1:-1;140967:14:0;23684:13:1;;140994:95:0::1;::::0;;;;;::::1;::::0;;;;;;140984:106;;140994:95:::1;140984:106:::0;;::::1;::::0;141101:28:::1;::::0;::::1;;::::0;;;:12:::1;:28:::0;;;;;141135:167:::1;::::0;::::1;::::0;;;;;;;::::1;::::0;;;;;;;;;140984:106;;-1:-1:-1;141101:28:0;141135:167;;;141236:25:::1;141182:15:::0;141256:4;141236:19:::1;:25::i;:::-;141135:167:::0;;::::1;::::0;;::::1;::::0;;;141101:202;;::::1;::::0;;::::1;::::0;;-1:-1:-1;141101: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;141408:12:::1;::::0;141368:96:::1;::::0;141408:12:::1;;141423:14:::0;141447:4:::1;141454:9:::0;141368:31:::1;:96::i;:::-;141534:23;::::0;:38:::1;::::0;141562:9;141534:27:::1;:38::i;:::-;141508:23;:64:::0;141619:33:::1;::::0;::::1;;::::0;;;:17:::1;:33:::0;;;;;;:48:::1;::::0;141657:9;141619:37:::1;:48::i;:::-;141583:33;::::0;::::1;;::::0;;;:17:::1;:33:::0;;;;;:84;;;;141736:52:::1;::::0;141601:14;;141783:4:::1;141736:23;:52::i;:::-;141806:68;::::0;;23939:25:1;;;23995:2;23980:18;;23973:34;;;24023:18;;;24016:34;;;141806:68:0::1;24086:55:1::0;;;24081:2;24066:18;;24059:83;141806:68:0;::::1;::::0;::::1;::::0;23926:3:1;23911:19;141806:68:0::1;;;;;;;140571:1311;;140334:1548:::0;;;;;;;:::o;145592:797::-;145716:28;145691:8;145701:4;110650:49;110674:7;110683:8;110693:5;110650:23;:49::i;:::-;145785:12:::1;:19:::0;145771:34:::1;::::0;::::1;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;-1:-1:-1;145771:34:0::1;;145757:48;;145821:9;145816:450;145840:12;:19:::0;145836:23;::::1;145816:450;;;145899:17;::::0;::::1;;::::0;;;:7:::1;:17;::::0;;;;;;;:20;;;;;;;;;145882:14;;:11;;145917:1;;145882:14;::::1;;;;;:::i;:::-;;;;;;:37;;;::::0;::::1;145957:1;145940:11;145952:1;145940:14;;;;;;;;:::i;:::-;;;;;;;:18;145936:319;;;145979:17;::::0;::::1;146002:1;145979:17:::0;;;:7:::1;:17;::::0;;;;;;;:20;;;;;;;;:24;146028:12:::1;:15:::0;;145997:1;;146028:15;::::1;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;146022:31;;;146054:19;146075:11;146087:1;146075:14;;;;;;;;:::i;:::-;;;;;;;146022:68;;;;;;;;;;;;;;;15899:42:1::0;15887:55;;;;15869:74;;15974:2;15959:18;;15952:34;15857:2;15842:18;;15695:297;146022:68:0::1;;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;146127:11;146139:1;146127:14;;;;;;;;:::i;:::-;;;;;;;146109:11;146121:1;146109:14;;;;;;;;:::i;:::-;;;;;;;;;:32;;;;;;;:::i;:::-;;;;;;;;146176:8;146165:74;;;146186:11;146198:1;146186:14;;;;;;;;:::i;:::-;;;;;;;146202:12;146215:1;146202:15;;;;;;;;:::i;:::-;;::::0;;;::::1;::::0;;;;::::1;::::0;146165:74:::1;::::0;;24355:25:1;;;146202:15:0::1;::::0;;::::1;24457:18:1::0;;;24450:43;;;;24529:15;;24509:18;;;24502:43;24343:2;24328:18;146165:74:0::1;;;;;;;145936:319;145861:3;;145816:450;;;-1:-1:-1::0;;;146334:29:0::1;::::0;;::::1;;::::0;;;:19:::1;:29;::::0;;;;146366:15:::1;146334:47:::0;;-1:-1:-1;145592:797:0;:::o;142908:1844::-;143351:13;:50;;;-1:-1:-1;143369:32:0;;;;;;;143368:33;143351:50;143347:240;;;143403:47;143414:14;143430:19;143403:10;:47::i;:::-;;143347:240;;;143523:52;143547:14;143563:4;143569:5;143523:23;:52::i;:::-;143608:28;143638:21;143663:33;143673:14;143689:6;143663:9;:33::i;:::-;143715:16;;143607:89;;-1:-1:-1;143607:89:0;-1:-1:-1;143715:26:0;;143707:54;;;;;;;24758:2:1;143707:54:0;;;24740:21:1;24797:2;24777:18;;;24770:30;24836:17;24816:18;;;24809:45;24871:18;;143707:54:0;24556:339:1;143707:54:0;143799:9;:26;;;143780:15;:45;;:71;;;-1:-1:-1;143829:14:0;;;;;;;;:22;;:14;:22;143780:71;:110;;;-1:-1:-1;143871:10:0;143855:27;;;;:15;:27;;;;;;;;:35;;:27;:35;143780:110;143772:145;;;;;;;25102:2:1;143772:145:0;;;25084:21:1;25141:2;25121:18;;;25114:30;25180:24;25160:18;;;25153:52;25222:18;;143772:145:0;24900:346:1;143772:145:0;143950:19;;;;143986:13;;143982:761;;144077:23;;:38;;144105:9;144077:27;:38::i;:::-;144051:23;:64;144166:33;;;;;;;:17;:33;;;;;;:48;;144204:9;144166:37;:48::i;:::-;144130:33;;;;;;;:17;:33;;;;;;;:84;;;;144286:12;:28;;;:43;;144315:13;;144286:43;;;;;;:::i;:::-;;;;;;;;;;;;144279:50;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;144406:51;144430:14;144446:4;144452;144406:23;:51::i;:::-;144586:12;;:53;;;;;:12;15887:55:1;;;144586:53:0;;;15869:74:1;15959:18;;;15952:34;;;144586:12:0;;;;:21;;15842:18:1;;144586:53:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;144661:70:0;;;25453:25:1;;;25509:2;25494:18;;25487:34;;;144661:70:0;25557:55:1;;;25537:18;;;25530:83;144661:70:0;;;;;;;;;;;25441:2:1;144661:70:0;;;143982:761;143032:1720;;;142908:1844;;;;:::o;133059:1806::-;133275:8;133271:46;;;133299:6;:4;:6::i;:::-;133449:19;133445:109;;;133518:24;133534:7;133518:15;:24::i;:::-;133484:31;;;;;;;:22;:31;;;;;:58;133445:109;133578:21;;;;133574:1284;;133792:27;133838:28;133885:27;133930:30;133952:7;133930:21;:30::i;:::-;133770:190;;;;;;134022:20;134034:7;134022:11;:20::i;:::-;134118:31;;;;;;;:22;:31;;;;;:54;;;134259:42;;;134255:590;;134322:19;134344:44;:19;134368;134344:23;:44::i;:::-;134432:22;;134322:66;;-1:-1:-1;134432:39:0;;134322:66;134432:26;:39::i;:::-;134407:22;:64;134519:36;:19;134543:11;134519:23;:36::i;:::-;134490:26;;;;;;;:17;:26;;;;;:65;-1:-1:-1;134255:590:0;;;134596:19;134618:44;:19;134642;134618:23;:44::i;:::-;134706:22;;134596:66;;-1:-1:-1;134706:39:0;;134596:66;134706:26;:39::i;:::-;134681:22;:64;134793:36;:19;134817:11;134793:23;:36::i;:::-;134764:26;;;;;;;:17;:26;;;;;:65;-1:-1:-1;134255:590:0;133601:1257;;;133574:1284;133059:1806;;;:::o;132294:509::-;132376:31;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;132376:31:0;132409:15;;132437:281;132461:28;;;;;;;:12;:28;;;;;:35;132457:39;;132437:281;;;132533:28;;;;;;;:12;:28;;;;;:31;;132562:1;;132533:31;;;;;;:::i;:::-;;;;;;;;;;;:38;;;132523:6;:48;132519:188;;132606:28;;;;;;;:12;:28;;;;;:31;;132635:1;;132606:31;;;;;;:::i;:::-;;;;;;;;;;;132591:46;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;132666:1;132656:11;;132686:5;;132519:188;132498:3;;132437:281;;;-1:-1:-1;132736:19:0;;:29;;132728:57;;;;;;;24758:2:1;132728:57:0;;;24740:21:1;24797:2;24777:18;;;24770:30;24836:17;24816:18;;;24809:45;24871:18;;132728:57:0;24556:339:1;132728:57:0;132294:509;;;;;:::o;36507:402::-;36732:51;;;36721:10;25905:15:1;;;36732:51:0;;;25887:34:1;25957:15;;;25937:18;;;25930:43;25989:18;;;;25982:34;;;36732:51:0;;;;;;;;;;25799: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;;;;;;;26521:2:1;36795:106:0;;;26503:21:1;26560:2;26540:18;;;26533:30;26599:34;26579:18;;;26572:62;26670:6;26650:18;;;26643:34;26694:19;;36795:106:0;26319:400:1;115459:133:0;115518:7;115545:39;115554:15;115571:12;;115545:8;:39::i;:::-;115538:46;;115459:133;:::o;146447:2384::-;146579:15;;146560:14;;146538:37;;146539:15;;146538:21;:37::i;:::-;:56;146534:933;;146623:8;;146615:31;146623:8;146615:31;146611:99;;146667:8;;;;;;;;;;;:25;;;:27;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;146611:99;147352:12;;:37;;;;;147383:4;147352:37;;;1575:74:1;147352:12:0;;;;;:22;;1548:18:1;;147352:37:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;147440:15:0;147423:14;:32;-1:-1:-1;;146534:933:0;147519:28;147550:64;147559:37;147581:14;;147560:15;147559:21;;:37;;;;:::i;:::-;147598:15;;147550:8;:64::i;:::-;147519:95;;147659:24;147686:16;:14;:16::i;:::-;147659:43;;147718:9;147713:1111;147737:12;:19;147733:23;;147713:1111;;;147832:16;147857:12;147870:1;147857:15;;;;;;;;:::i;:::-;;;;;;;;;;;147851:47;;;;;147892:4;147851:47;;;1575:74:1;147857:15:0;;;;;147851:32;;1548:18:1;;147851:47:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;147832:66;;148063:40;148082:20;148063:11;148075:1;148063:14;;;;;;;;:::i;:40::-;148045:11;148057:1;148045:14;;;;;;;;:::i;:::-;;;;;;;;;:58;;;;;;;:::i;:::-;;;;;;;;148193:7;148201:1;148193:10;;;;;;;;:::i;:::-;;;;;;;148166:21;148188:1;148166:24;;;;;;;;:::i;:::-;;;;;;;;:37;;;;148366:15;148384:34;148403:11;148415:1;148403:14;;;;;;;;:::i;:::-;;;;;;;;;148384:11;148396:1;148384:14;;;;;;;;:::i;:::-;;;;;;;;;:18;;:34;;;;:::i;:::-;148366:52;;148496:7;148484:8;:19;148480:316;;148604:1;148587:11;148599:1;148587:14;;;;;;;;:::i;:::-;;;;;;;;;;:18;148480:316;;;148671:13;148687:21;:8;148700:7;148687:12;:21::i;:::-;148671:37;;148748:28;148760:15;;148749:5;148748:11;;:28;;;;:::i;:::-;148731:11;148743:1;148731:14;;;;;;;;:::i;:::-;;;;;;;;;;:45;-1:-1:-1;148480:316:0;-1:-1:-1;;147758:3:0;;147713: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;:::-;3141:17;2995:192;-1:-1:-1;;;;;2995:192:0:o;5039:345::-;5125:7;5227:12;5220:5;5212:28;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;5251:9:0;5263:5;5267:1;5263;:5;:::i;138078:417::-;138140:21;;;;138136:352;;138219:25;138247:15;138254:7;138247:6;:15::i;:::-;138219:43;;138282:9;138277:200;138301:12;:19;138297:23;;138277:200;;;138369:8;138378:1;138369:11;;;;;;;;:::i;:::-;;;;;;;;;;;;138347:16;;;;;;;:7;:16;;;;;;:19;;;;;;;;;;:33;138437:21;:24;;138364:1;;138437:24;;;;;;:::i;:::-;;;;;;;;;;;;;138399:32;;;;;:23;:32;;;;;;:35;;;;;;;;:62;138322:3;;138277:200;;138136:352;138078:417;:::o;14:154:1:-;100:42;93:5;89:54;82:5;79:65;69:93;;158:1;155;148:12;173:247;232:6;285:2;273:9;264:7;260:23;256:32;253:52;;;301:1;298;291:12;253:52;340:9;327:23;359:31;384:5;359:31;:::i;425:632::-;596:2;648:21;;;718:13;;621:18;;;740:22;;;567:4;;596:2;819:15;;;;793:2;778:18;;;567:4;862:169;876:6;873:1;870:13;862:169;;;937:13;;925:26;;1006:15;;;;971:12;;;;898:1;891:9;862:169;;;-1:-1:-1;1048:3:1;;425:632;-1:-1:-1;;;;;;425:632:1:o;1062:180::-;1121:6;1174:2;1162:9;1153:7;1149:23;1145:32;1142:52;;;1190:1;1187;1180:12;1142:52;-1:-1:-1;1213:23:1;;1062:180;-1:-1:-1;1062:180:1:o;1660:248::-;1728:6;1736;1789:2;1777:9;1768:7;1764:23;1760:32;1757:52;;;1805:1;1802;1795:12;1757:52;-1:-1:-1;;1828:23:1;;;1898:2;1883:18;;;1870:32;;-1:-1:-1;1660:248:1:o;2159:1011::-;2388:2;2440:21;;;2510:13;;2413:18;;;2532:22;;;2359:4;;2388:2;2573;;2591:18;;;;2632:15;;;2359:4;2675:469;2689:6;2686:1;2683:13;2675:469;;;2748:13;;2786:9;;2774:22;;2836:11;;;2830:18;2816:12;;;2809:40;2889:11;;;2883:18;2869:12;;;2862:40;2925:4;2969:11;;;2963:18;2949:12;;;2942:40;3005:4;3049:11;;;3043:18;3029:12;;;3022:40;3091:4;3082:14;;;;3119:15;;;;2711:1;2704:9;2675:469;;;-1:-1:-1;3161:3:1;;2159:1011;-1:-1:-1;;;;;;;2159:1011:1:o;3175:452::-;3261:6;3269;3277;3285;3338:3;3326:9;3317:7;3313:23;3309:33;3306:53;;;3355:1;3352;3345:12;3306:53;3394:9;3381:23;3413:31;3438:5;3413:31;:::i;:::-;3463:5;3515:2;3500:18;;3487:32;;-1:-1:-1;3566:2:1;3551:18;;3538:32;;3617:2;3602:18;3589:32;;-1:-1:-1;3175:452:1;-1:-1:-1;;;3175:452:1:o;3824:250::-;3909:1;3919:113;3933:6;3930:1;3927:13;3919:113;;;4009:11;;;4003:18;3990:11;;;3983:39;3955:2;3948:10;3919:113;;;-1:-1:-1;;4066:1:1;4048:16;;4041:27;3824:250::o;4079:455::-;4228:2;4217:9;4210:21;4191:4;4260:6;4254:13;4303:6;4298:2;4287:9;4283:18;4276:34;4319:79;4391:6;4386:2;4375:9;4371:18;4366:2;4358:6;4354:15;4319:79;:::i;:::-;4450:2;4438:15;4455:66;4434:88;4419:104;;;;4525:2;4415:113;;4079:455;-1:-1:-1;;4079:455:1:o;4539:316::-;4616:6;4624;4632;4685:2;4673:9;4664:7;4660:23;4656:32;4653:52;;;4701:1;4698;4691:12;4653:52;-1:-1:-1;;4724:23:1;;;4794:2;4779:18;;4766:32;;-1:-1:-1;4845:2:1;4830:18;;;4817:32;;4539:316;-1:-1:-1;4539:316:1:o;5127:315::-;5195:6;5203;5256:2;5244:9;5235:7;5231:23;5227:32;5224:52;;;5272:1;5269;5262:12;5224:52;5311:9;5298:23;5330:31;5355:5;5330:31;:::i;:::-;5380:5;5432:2;5417:18;;;;5404:32;;-1:-1:-1;;;5127:315:1:o;6239:118::-;6325:5;6318:13;6311:21;6304:5;6301:32;6291:60;;6347:1;6344;6337:12;6362:309;6427:6;6435;6488:2;6476:9;6467:7;6463:23;6459:32;6456:52;;;6504:1;6501;6494:12;6456:52;6540:9;6527:23;6517:33;;6600:2;6589:9;6585:18;6572:32;6613:28;6635:5;6613:28;:::i;:::-;6660:5;6650:15;;;6362:309;;;;;:::o;6676:388::-;6744:6;6752;6805:2;6793:9;6784:7;6780:23;6776:32;6773:52;;;6821:1;6818;6811:12;6773:52;6860:9;6847:23;6879:31;6904:5;6879:31;:::i;:::-;6929:5;-1:-1:-1;6986:2:1;6971:18;;6958:32;6999:33;6958:32;6999:33;:::i;8084:184::-;8136:77;8133:1;8126:88;8233:4;8230:1;8223:15;8257:4;8254:1;8247:15;8273:184;8325:77;8322:1;8315:88;8422:4;8419:1;8412:15;8446:4;8443:1;8436:15;8812:184;8864:77;8861:1;8854:88;8961:4;8958:1;8951:15;8985:4;8982:1;8975:15;9001:168;9074:9;;;9105;;9122:15;;;9116:22;;9102:37;9092:71;;9143:18;;:::i;9174:274::-;9214:1;9240;9230:189;;9275:77;9272:1;9265:88;9376:4;9373:1;9366:15;9404:4;9401:1;9394:15;9230:189;-1:-1:-1;9433:9:1;;9174:274::o;11976:184::-;12046:6;12099:2;12087:9;12078:7;12074:23;12070:32;12067:52;;;12115:1;12112;12105:12;12067:52;-1:-1:-1;12138:16:1;;11976:184;-1:-1:-1;11976:184:1:o;12519:437::-;12598:1;12594:12;;;;12641;;;12662:61;;12716:4;12708:6;12704:17;12694:27;;12662:61;12769:2;12761:6;12758:14;12738:18;12735:38;12732:218;;12806:77;12803:1;12796:88;12907:4;12904:1;12897:15;12935:4;12932:1;12925:15;12961:251;13031:6;13084:2;13072:9;13063:7;13059:23;13055:32;13052:52;;;13100:1;13097;13090:12;13052:52;13132:9;13126:16;13151:31;13176:5;13151:31;:::i;14678:128::-;14745:9;;;14766:11;;;14763:37;;;14780:18;;:::i;14811:125::-;14876:9;;;14897:10;;;14894:36;;;14910:18;;:::i;15997:245::-;16064:6;16117:2;16105:9;16096:7;16092:23;16088:32;16085:52;;;16133:1;16130;16123:12;16085:52;16165:9;16159:16;16184:28;16206:5;16184:28;:::i;18242:179::-;18320:13;;18373:22;18362:34;;18352:45;;18342:73;;18411:1;18408;18401:12;18426:473;18529:6;18537;18545;18553;18561;18614:3;18602:9;18593:7;18589:23;18585:33;18582:53;;;18631:1;18628;18621:12;18582:53;18654:39;18683:9;18654:39;:::i;:::-;18644:49;;18733:2;18722:9;18718:18;18712:25;18702:35;;18777:2;18766:9;18762:18;18756:25;18746:35;;18821:2;18810:9;18806:18;18800:25;18790:35;;18844:49;18888:3;18877:9;18873:19;18844:49;:::i;:::-;18834:59;;18426:473;;;;;;;;:::o;26027:287::-;26156:3;26194:6;26188:13;26210:66;26269:6;26264:3;26257:4;26249:6;26245:17;26210:66;:::i;:::-;26292:16;;;;;26027:287;-1:-1:-1;;26027:287:1:o
Swarm Source
ipfs://e4716ab1889f316057138fe44c637fd8d9c0ea22572601847b8dc238ae47ebc7
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$379.17
Net Worth in ETH
0.128271
Token Allocations
FXS
50.90%
ARB
33.16%
CRV
15.94%
Multichain Portfolio | 35 Chains
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.