creation_sourcecode: // 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/Curve/IFraxGaugeFXSRewardsDistributor.sol
  
  // Original license: SPDX_License_Identifier: GPL-2.0-or-later
  
  interface IFraxGaugeFXSRewardsDistributor {
    function acceptOwnership() external;
    function curator_address() external view returns(address);
    function currentReward(address gauge_address) external view returns(uint256 reward_amount);
    function distributeReward(address gauge_address) external returns(uint256 weeks_elapsed, uint256 reward_tally);
    function distributionsOn() external view returns(bool);
    function gauge_whitelist(address) external view returns(bool);
    function is_middleman(address) external view returns(bool);
    function last_time_gauge_paid(address) external view returns(uint256);
    function nominateNewOwner(address _owner) external;
    function nominatedOwner() external view returns(address);
    function owner() external view returns(address);
    function recoverERC20(address tokenAddress, uint256 tokenAmount) external;
    function setCurator(address _new_curator_address) external;
    function setGaugeController(address _gauge_controller_address) external;
    function setGaugeState(address _gauge_address, bool _is_middleman, bool _is_active) external;
    function setTimelock(address _new_timelock) external;
    function timelock_address() external view returns(address);
    function toggleDistributions() external;
  }
  
  
  // File contracts/Common/Context.sol
  
  // 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/Fraxferry/IFraxferry.sol
  
  // Original license: SPDX_License_Identifier: GPL-2.0-or-later
  
  interface IFraxferry {
      struct Transaction {
          address user;
          uint64 amount;
          uint32 timestamp;
      }
  
      struct Batch {
          uint64 start;
          uint64 end;
          uint64 departureTime;
          uint64 status;
          bytes32 hash;
      }
  
      struct BatchData {
          uint startTransactionNo;
          Transaction[] transactions;
      }
  
      function FEE () external view returns (uint256);
      function MIN_WAIT_PERIOD_ADD () external view returns (uint256);
      function MIN_WAIT_PERIOD_EXECUTE () external view returns (uint256);
      function REDUCED_DECIMALS () external view returns (uint256);
      function acceptOwnership () external;
      function batches (uint256) external view returns (uint64 start, uint64 end, uint64 departureTime, uint64 status, bytes32 hash);
      function cancelled (uint256) external view returns (bool);
      function captain () external view returns (address);
      function chainid () external view returns (uint256);
      function crewmembers (address) external view returns (bool);
      function depart (uint256 start, uint256 end, bytes32 hash) external;
      function disembark (BatchData memory batchData) external;
      function disputeBatch (uint256 batchNo, bytes32 hash) external;
      function embark (uint256 amount) external;
      function embarkWithRecipient (uint256 amount, address recipient) external;
      function embarkWithSignature (uint256 _amount, address recipient, uint256 deadline, bool approveMax, uint8 v, bytes32 r, bytes32 s) external;
      function execute (address _to, uint256 _value, bytes memory _data) external returns (bool, bytes memory);
      function executeIndex () external view returns (uint256);
      function firstOfficer () external view returns (address);
      function getBatchAmount (uint256 start, uint256 end) external view returns (uint256 totalAmount);
      function getBatchData (uint256 start, uint256 end) external view returns (BatchData memory data);
      function getNextBatch (uint256 _start, uint256 max) external view returns (uint256 start, uint256 end, bytes32 hash);
      function getTransactionsHash (uint256 start, uint256 end) external view returns (bytes32);
      function jettison (uint256 index, bool cancel) external;
      function jettisonGroup (uint256[] memory indexes, bool cancel) external;
      function noBatches () external view returns (uint256);
      function noTransactions () external view returns (uint256);
      function nominateNewOwner (address newOwner) external;
      function nominatedOwner () external view returns (address);
      function owner () external view returns (address);
      function pause () external;
      function paused () external view returns (bool);
      function removeBatches (uint256 batchNo) external;
      function sendTokens (address receiver, uint256 amount) external;
      function setCaptain (address newCaptain) external;
      function setCrewmember (address crewmember, bool set) external;
      function setFee (uint256 _FEE) external;
      function setFirstOfficer (address newFirstOfficer) external;
      function setMinWaitPeriods (uint256 _MIN_WAIT_PERIOD_ADD, uint256 _MIN_WAIT_PERIOD_EXECUTE) external;
      function targetChain () external view returns (uint256);
      function targetToken () external view returns (address);
      function token () external view returns (address);
      function transactions (uint256) external view returns (address user, uint64 amount, uint32 timestamp);
      function unPause () external;
  }
  
  
  // 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/FraxMiddlemanGaugeV2.sol
  
  // Original license: SPDX_License_Identifier: GPL-2.0-or-later
  
  // ====================================================================
  // |     ______                   _______                             |
  // |    / _____________ __  __   / ____(_____  ____ _____  ________   |
  // |   / /_  / ___/ __ `| |/_/  / /_  / / __ \/ __ `/ __ \/ ___/ _ \  |
  // |  / __/ / /  / /_/ _>  <   / __/ / / / / / /_/ / / / / /__/  __/  |
  // | /_/   /_/   \__,_/_/|_|  /_/   /_/_/ /_/\__,_/_/ /_/\___/\___/   |
  // |                                                                  |
  // ====================================================================
  // ======================= FraxMiddlemanGaugeV2 =======================
  // ====================================================================
  // Looks at the gauge controller contract and pushes out FXS rewards once
  // a week to the gauges (farms).
  // This contract is what gets added to the gauge as a 'slice'
  // V2: Uses Fraxferry instead of miscellaneous 3rd-party bridges
  
  // 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
  
  
  
  
  
  
  
  
  
  contract FraxMiddlemanGaugeV2 is Owned, ReentrancyGuard {
      using SafeMath for uint256;
      using SafeERC20 for ERC20;
  
      /* ========== STATE VARIABLES ========== */
  
      // Instances and addresses
      address public reward_token_address = 0x3432B6A60D23Ca0dFCa7761B7ab56459D9C964D0; // FXS
      address public rewards_distributor_address;
  
      // Informational
      string public name;
  
      // Admin addresses
      address public timelock_address;
  
      // Gauge-related
      IFraxferry public ferry;
      address public destination_address;
  
  
      /* ========== MODIFIERS ========== */
  
      modifier onlyByOwnGov() {
          require(msg.sender == owner || msg.sender == timelock_address, "Not owner or timelock");
          _;
      }
  
      modifier onlyRewardsDistributor() {
          require(msg.sender == rewards_distributor_address, "Not rewards distributor");
          _;
      }
  
      /* ========== CONSTRUCTOR ========== */
  
      constructor (
          address _owner,
          address _timelock_address,
          address _rewards_distributor_address,
          address _ferry_address,
          address _destination_address,
          string memory _name
      ) Owned(_owner) {
          timelock_address = _timelock_address;
  
          rewards_distributor_address = _rewards_distributor_address;
  
          ferry = IFraxferry(_ferry_address);
          destination_address = _destination_address;
  
          name = _name;
      }
  
      /* ========== MUTATIVE FUNCTIONS ========== */
  
      // Callable only by the rewards distributor
      function pullAndBridge(uint256 reward_amount) external onlyRewardsDistributor nonReentrant {
          require(address(ferry) != address(0), "Invalid bridge address");
  
          // Pull in the rewards from the rewards distributor
          TransferHelper.safeTransferFrom(reward_token_address, rewards_distributor_address, address(this), reward_amount);
  
          // Logic here
          ERC20(reward_token_address).approve(address(ferry), reward_amount);
          ferry.embarkWithRecipient(reward_amount, destination_address);
  
      }
  
      /* ========== 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 setTimelock(address _new_timelock) external onlyByOwnGov {
          timelock_address = _new_timelock;
      }
  
      function setBridgeInfo(address _ferry_address, address _destination_address) external onlyByOwnGov {
          ferry = IFraxferry(_ferry_address);
          
          // Overridden cross-chain destination address
          destination_address = _destination_address;
  
          
          emit BridgeInfoChanged(_ferry_address, _destination_address);
      }
  
      function setRewardsDistributor(address _rewards_distributor_address) external onlyByOwnGov {
          rewards_distributor_address = _rewards_distributor_address;
      }
  
      /* ========== EVENTS ========== */
  
      event RecoveredERC20(address token, uint256 amount);
      event BridgeInfoChanged(address ferry_address, address destination_address);
  }