ETH Price: $2,426.31 (-2.74%)

Transaction Decoder

Block:
10755559 at Aug-29-2020 12:09:36 PM +UTC
Transaction Fee:
0.004753659 ETH $11.53
Gas Used:
93,209 Gas / 51 Gwei

Emitted Events:

273 YAMDelegator.Transfer( from=[Receiver] YAMIncentivizer, to=[Sender] 0x9c1ba1c051f0b5323fb474a0afc7a0e103c40f55, amount=3621046657930641725354 )
274 YAMIncentivizer.RewardPaid( user=[Sender] 0x9c1ba1c051f0b5323fb474a0afc7a0e103c40f55, reward=3621046657930641725354 )

Account State Difference:

  Address   Before After State Difference Code
0x0e2298E3...c3f55DA16
(Spark Pool)
32.691463726700162253 Eth32.696217385700162253 Eth0.004753659
0x9c1ba1C0...103c40f55
0.488234479822325404 Eth
Nonce: 185
0.483480820822325404 Eth
Nonce: 186
0.004753659
0xADDBCd6A...a54497F4c
(Yam.Finance: yCrv Uniswap Pool)

Execution Trace

YAMIncentivizer.CALL( )
  • YAMDelegator.CALL( )
  • YAMDelegator.transfer( dst=0x9c1ba1C051f0B5323fb474a0Afc7A0e103c40f55, amount=3621046657930641725354 ) => ( True )
    • YAMDelegate.transfer( to=0x9c1ba1C051f0B5323fb474a0Afc7A0e103c40f55, value=3621046657930641725354 ) => ( True )
      File 1 of 3: YAMIncentivizer
      /**
       *Submitted for verification at Etherscan.io on 2020-07-27
      */
      
      /**
       *Submitted for verification at Etherscan.io on 2020-07-26
      */
      
      /**
       *Submitted for verification at Etherscan.io on 2020-07-17
      */
      
      /*
         ____            __   __        __   _
        / __/__ __ ___  / /_ / /  ___  / /_ (_)__ __
       _\ \ / // // _ \/ __// _ \/ -_)/ __// / \ \ /
      /___/ \_, //_//_/\__//_//_/\__/ \__//_/ /_\_\
           /___/
      
      * Synthetix: YAMIncentives.sol
      *
      * Docs: https://docs.synthetix.io/
      *
      *
      * MIT License
      * ===========
      *
      * Copyright (c) 2020 Synthetix
      *
      * Permission is hereby granted, free of charge, to any person obtaining a copy
      * of this software and associated documentation files (the "Software"), to deal
      * in the Software without restriction, including without limitation the rights
      * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
      * copies of the Software, and to permit persons to whom the Software is
      * furnished to do so, subject to the following conditions:
      *
      * The above copyright notice and this permission notice shall be included in all
      * copies or substantial portions of the Software.
      *
      * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
      * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
      * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
      */
      
      // File: @openzeppelin/contracts/math/Math.sol
      
      pragma solidity ^0.5.0;
      
      /**
       * @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);
          }
      }
      
      // File: @openzeppelin/contracts/math/SafeMath.sol
      
      pragma solidity ^0.5.0;
      
      /**
       * @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: @openzeppelin/contracts/GSN/Context.sol
      
      pragma solidity ^0.5.0;
      
      /*
       * @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.
       */
      contract Context {
          // Empty internal constructor, to prevent people from mistakenly deploying
          // an instance of this contract, which should be used via inheritance.
          constructor () internal { }
          // solhint-disable-previous-line no-empty-blocks
      
          function _msgSender() internal view returns (address payable) {
              return msg.sender;
          }
      
          function _msgData() internal view returns (bytes memory) {
              this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
              return msg.data;
          }
      }
      
      // File: @openzeppelin/contracts/ownership/Ownable.sol
      
      pragma solidity ^0.5.0;
      
      /**
       * @dev Contract module which provides a basic access control mechanism, where
       * there is an account (an owner) that can be granted exclusive access to
       * specific functions.
       *
       * This module is used through inheritance. It will make available the modifier
       * `onlyOwner`, which can be applied to your functions to restrict their use to
       * the owner.
       */
      contract Ownable is Context {
          address private _owner;
      
          event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
      
          /**
           * @dev Initializes the contract setting the deployer as the initial owner.
           */
          constructor () internal {
              _owner = _msgSender();
              emit OwnershipTransferred(address(0), _owner);
          }
      
          /**
           * @dev Returns the address of the current owner.
           */
          function owner() public view returns (address) {
              return _owner;
          }
      
          /**
           * @dev Throws if called by any account other than the owner.
           */
          modifier onlyOwner() {
              require(isOwner(), "Ownable: caller is not the owner");
              _;
          }
      
          /**
           * @dev Returns true if the caller is the current owner.
           */
          function isOwner() public view returns (bool) {
              return _msgSender() == _owner;
          }
      
          /**
           * @dev Leaves the contract without owner. It will not be possible to call
           * `onlyOwner` functions anymore. Can only be called by the current owner.
           *
           * NOTE: Renouncing ownership will leave the contract without an owner,
           * thereby removing any functionality that is only available to the owner.
           */
          function renounceOwnership() public onlyOwner {
              emit OwnershipTransferred(_owner, address(0));
              _owner = address(0);
          }
      
          /**
           * @dev Transfers ownership of the contract to a new account (`newOwner`).
           * Can only be called by the current owner.
           */
          function transferOwnership(address newOwner) public onlyOwner {
              _transferOwnership(newOwner);
          }
      
          /**
           * @dev Transfers ownership of the contract to a new account (`newOwner`).
           */
          function _transferOwnership(address newOwner) internal {
              require(newOwner != address(0), "Ownable: new owner is the zero address");
              emit OwnershipTransferred(_owner, newOwner);
              _owner = newOwner;
          }
      }
      
      // File: @openzeppelin/contracts/token/ERC20/IERC20.sol
      
      pragma solidity ^0.5.0;
      
      /**
       * @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);
          function mint(address account, uint amount) external;
      
          /**
           * @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: @openzeppelin/contracts/utils/Address.sol
      
      pragma solidity ^0.5.5;
      
      /**
       * @dev Collection of functions related to the address type
       */
      library Address {
          /**
           * @dev Returns true if `account` is a contract.
           *
           * This test is non-exhaustive, and there may be false-negatives: during the
           * execution of a contract's constructor, its address will be reported as
           * not containing 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.
           */
          function isContract(address account) internal view returns (bool) {
              // This method relies in extcodesize, which returns 0 for contracts in
              // construction, since the code is only stored at the end of the
              // constructor execution.
      
              // According to EIP-1052, 0x0 is the value returned for not-yet created accounts
              // and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned
              // for accounts without code, i.e. `keccak256('')`
              bytes32 codehash;
              bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;
              // solhint-disable-next-line no-inline-assembly
              assembly { codehash := extcodehash(account) }
              return (codehash != 0x0 && codehash != accountHash);
          }
      
          /**
           * @dev Converts an `address` into `address payable`. Note that this is
           * simply a type cast: the actual underlying value is not changed.
           *
           * _Available since v2.4.0._
           */
          function toPayable(address account) internal pure returns (address payable) {
              return address(uint160(account));
          }
      
          /**
           * @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].
           *
           * _Available since v2.4.0._
           */
          function sendValue(address payable recipient, uint256 amount) internal {
              require(address(this).balance >= amount, "Address: insufficient balance");
      
              // solhint-disable-next-line avoid-call-value
              (bool success, ) = recipient.call.value(amount)("");
              require(success, "Address: unable to send value, recipient may have reverted");
          }
      }
      
      // File: @openzeppelin/contracts/token/ERC20/SafeERC20.sol
      
      pragma solidity ^0.5.0;
      
      
      
      
      /**
       * @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 ERC20;` 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));
          }
      
          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.
      
              // A Solidity high level call has three parts:
              //  1. The target address is checked to verify it contains contract code
              //  2. The call itself is made, and success asserted
              //  3. The return value is decoded, which in turn checks the size of the returned data.
              // solhint-disable-next-line max-line-length
              require(address(token).isContract(), "SafeERC20: call to non-contract");
      
              // solhint-disable-next-line avoid-low-level-calls
              (bool success, bytes memory returndata) = address(token).call(data);
              require(success, "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/IRewardDistributionRecipient.sol
      
      pragma solidity ^0.5.0;
      
      
      
      contract IRewardDistributionRecipient is Ownable {
          address rewardDistribution;
      
          function notifyRewardAmount(uint256 reward) external;
      
          modifier onlyRewardDistribution() {
              require(_msgSender() == rewardDistribution, "Caller is not reward distribution");
              _;
          }
      
          function setRewardDistribution(address _rewardDistribution)
              external
              onlyOwner
          {
              rewardDistribution = _rewardDistribution;
          }
      }
      
      // File: contracts/CurveRewards.sol
      
      pragma solidity ^0.5.0;
      
      
      
      
      
      
      contract LPTokenWrapper {
          using SafeMath for uint256;
          using SafeERC20 for IERC20;
      
          IERC20 public uni_lp = IERC20(0x2C7a51A357d5739C5C74Bf3C96816849d2c9F726);
      
          uint256 private _totalSupply;
      
          mapping(address => uint256) private _balances;
      
          function totalSupply() public view returns (uint256) {
              return _totalSupply;
          }
      
          function balanceOf(address account) public view returns (uint256) {
              return _balances[account];
          }
      
          function stake(uint256 amount) public {
              _totalSupply = _totalSupply.add(amount);
              _balances[msg.sender] = _balances[msg.sender].add(amount);
              uni_lp.safeTransferFrom(msg.sender, address(this), amount);
          }
      
          function withdraw(uint256 amount) public {
              _totalSupply = _totalSupply.sub(amount);
              _balances[msg.sender] = _balances[msg.sender].sub(amount);
              uni_lp.safeTransfer(msg.sender, amount);
          }
      }
      
      interface YAM {
          function yamsScalingFactor() external returns (uint256);
          function mint(address to, uint256 amount) external;
      }
      
      contract YAMIncentivizer is LPTokenWrapper, IRewardDistributionRecipient {
          IERC20 public yam = IERC20(0x0e2298E3B3390e3b945a5456fBf59eCc3f55DA16);
          uint256 public constant DURATION = 625000;
      
          uint256 public initreward = 15 * 10**5 * 10**18; // 1.5m
          uint256 public starttime = 1597172400 + 24 hours; // 2020-08-12 19:00:00 (UTC UTC +00:00)
          uint256 public periodFinish = 0;
          uint256 public rewardRate = 0;
          uint256 public lastUpdateTime;
          uint256 public rewardPerTokenStored;
          mapping(address => uint256) public userRewardPerTokenPaid;
          mapping(address => uint256) public rewards;
      
      
          event RewardAdded(uint256 reward);
          event Staked(address indexed user, uint256 amount);
          event Withdrawn(address indexed user, uint256 amount);
          event RewardPaid(address indexed user, uint256 reward);
      
          modifier updateReward(address account) {
              rewardPerTokenStored = rewardPerToken();
              lastUpdateTime = lastTimeRewardApplicable();
              if (account != address(0)) {
                  rewards[account] = earned(account);
                  userRewardPerTokenPaid[account] = rewardPerTokenStored;
              }
              _;
          }
      
          function lastTimeRewardApplicable() public view returns (uint256) {
              return Math.min(block.timestamp, periodFinish);
          }
      
          function rewardPerToken() public view returns (uint256) {
              if (totalSupply() == 0) {
                  return rewardPerTokenStored;
              }
              return
                  rewardPerTokenStored.add(
                      lastTimeRewardApplicable()
                          .sub(lastUpdateTime)
                          .mul(rewardRate)
                          .mul(1e18)
                          .div(totalSupply())
                  );
          }
      
          function earned(address account) public view returns (uint256) {
              return
                  balanceOf(account)
                      .mul(rewardPerToken().sub(userRewardPerTokenPaid[account]))
                      .div(1e18)
                      .add(rewards[account]);
          }
      
          // stake visibility is public as overriding LPTokenWrapper's stake() function
          function stake(uint256 amount) public updateReward(msg.sender) checkhalve checkStart {
              require(amount > 0, "Cannot stake 0");
              super.stake(amount);
              emit Staked(msg.sender, amount);
          }
      
          function withdraw(uint256 amount) public updateReward(msg.sender) checkStart {
              require(amount > 0, "Cannot withdraw 0");
              super.withdraw(amount);
              emit Withdrawn(msg.sender, amount);
          }
      
          function exit() external {
              withdraw(balanceOf(msg.sender));
              getReward();
          }
      
          function getReward() public updateReward(msg.sender) checkhalve checkStart {
              uint256 reward = earned(msg.sender);
              if (reward > 0) {
                  rewards[msg.sender] = 0;
                  uint256 scalingFactor = YAM(address(yam)).yamsScalingFactor();
                  uint256 trueReward = reward.mul(scalingFactor).div(10**18);
                  yam.safeTransfer(msg.sender, trueReward);
                  emit RewardPaid(msg.sender, trueReward);
              }
          }
      
          modifier checkhalve() {
              if (block.timestamp >= periodFinish) {
                  initreward = initreward.mul(50).div(100);
                  uint256 scalingFactor = YAM(address(yam)).yamsScalingFactor();
                  uint256 newRewards = initreward.mul(scalingFactor).div(10**18);
                  yam.mint(address(this), newRewards);
      
                  rewardRate = initreward.div(DURATION);
                  periodFinish = block.timestamp.add(DURATION);
                  emit RewardAdded(initreward);
              }
              _;
          }
      
          modifier checkStart(){
              require(block.timestamp >= starttime,"not start");
              _;
          }
      
      
          function notifyRewardAmount(uint256 reward)
              external
              onlyRewardDistribution
              updateReward(address(0))
          {
              if (block.timestamp > starttime) {
                if (block.timestamp >= periodFinish) {
                    rewardRate = reward.div(DURATION);
                } else {
                    uint256 remaining = periodFinish.sub(block.timestamp);
                    uint256 leftover = remaining.mul(rewardRate);
                    rewardRate = reward.add(leftover).div(DURATION);
                }
                lastUpdateTime = block.timestamp;
                periodFinish = block.timestamp.add(DURATION);
                emit RewardAdded(reward);
              } else {
                require(yam.balanceOf(address(this)) == 0, "already initialized");
                yam.mint(address(this), initreward);
                rewardRate = initreward.div(DURATION);
                lastUpdateTime = starttime;
                periodFinish = starttime.add(DURATION);
                emit RewardAdded(reward);
              }
          }
      
      
          // This function allows governance to take unsupported tokens out of the
          // contract, since this one exists longer than the other pools.
          // This is in an effort to make someone whole, should they seriously
          // mess up. There is no guarantee governance will vote to return these.
          // It also allows for removal of airdropped tokens.
          function governanceRecoverUnsupported(IERC20 _token, uint256 amount, address to)
              external
          {
              // only gov
              require(msg.sender == owner(), "!governance");
              // cant take staked asset
              require(_token != uni_lp, "uni_lp");
              // cant take reward asset
              require(_token != yam, "yam");
      
              // transfer to
              _token.safeTransfer(to, amount);
          }
      }

      File 2 of 3: YAMDelegator
      pragma solidity 0.5.17;
      
      
      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.
           */
          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.
           */
          function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
              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.
           */
          function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
              require(b != 0, errorMessage);
              return a % b;
          }
      }
      
      
      contract YAMTokenStorage {
      
          using SafeMath for uint256;
      
          /**
           * @dev Guard variable for re-entrancy checks. Not currently used
           */
          bool internal _notEntered;
      
          /**
           * @notice EIP-20 token name for this token
           */
          string public name;
      
          /**
           * @notice EIP-20 token symbol for this token
           */
          string public symbol;
      
          /**
           * @notice EIP-20 token decimals for this token
           */
          uint8 public decimals;
      
          /**
           * @notice Governor for this contract
           */
          address public gov;
      
          /**
           * @notice Pending governance for this contract
           */
          address public pendingGov;
      
          /**
           * @notice Approved rebaser for this contract
           */
          address public rebaser;
      
          /**
           * @notice Reserve address of YAM protocol
           */
          address public incentivizer;
      
          /**
           * @notice Total supply of YAMs
           */
          uint256 public totalSupply;
      
          /**
           * @notice Internal decimals used to handle scaling factor
           */
          uint256 public constant internalDecimals = 10**24;
      
          /**
           * @notice Used for percentage maths
           */
          uint256 public constant BASE = 10**18;
      
          /**
           * @notice Scaling factor that adjusts everyone's balances
           */
          uint256 public yamsScalingFactor;
      
          mapping (address => uint256) internal _yamBalances;
      
          mapping (address => mapping (address => uint256)) internal _allowedFragments;
      
          uint256 public initSupply;
      
      }
      
      
      contract YAMGovernanceStorage {
          /// @notice A record of each accounts delegate
          mapping (address => address) internal _delegates;
      
          /// @notice A checkpoint for marking number of votes from a given block
          struct Checkpoint {
              uint32 fromBlock;
              uint256 votes;
          }
      
          /// @notice A record of votes checkpoints for each account, by index
          mapping (address => mapping (uint32 => Checkpoint)) public checkpoints;
      
          /// @notice The number of checkpoints for each account
          mapping (address => uint32) public numCheckpoints;
      
          /// @notice The EIP-712 typehash for the contract's domain
          bytes32 public constant DOMAIN_TYPEHASH = keccak256("EIP712Domain(string name,uint256 chainId,address verifyingContract)");
      
          /// @notice The EIP-712 typehash for the delegation struct used by the contract
          bytes32 public constant DELEGATION_TYPEHASH = keccak256("Delegation(address delegatee,uint256 nonce,uint256 expiry)");
      
          /// @notice A record of states for signing / validating signatures
          mapping (address => uint) public nonces;
      }
      
      
      contract YAMTokenInterface is YAMTokenStorage, YAMGovernanceStorage {
      
          /// @notice An event thats emitted when an account changes its delegate
          event DelegateChanged(address indexed delegator, address indexed fromDelegate, address indexed toDelegate);
      
          /// @notice An event thats emitted when a delegate account's vote balance changes
          event DelegateVotesChanged(address indexed delegate, uint previousBalance, uint newBalance);
      
          /**
           * @notice Event emitted when tokens are rebased
           */
          event Rebase(uint256 epoch, uint256 prevYamsScalingFactor, uint256 newYamsScalingFactor);
      
          /*** Gov Events ***/
      
          /**
           * @notice Event emitted when pendingGov is changed
           */
          event NewPendingGov(address oldPendingGov, address newPendingGov);
      
          /**
           * @notice Event emitted when gov is changed
           */
          event NewGov(address oldGov, address newGov);
      
          /**
           * @notice Sets the rebaser contract
           */
          event NewRebaser(address oldRebaser, address newRebaser);
      
          /**
           * @notice Sets the incentivizer contract
           */
          event NewIncentivizer(address oldIncentivizer, address newIncentivizer);
      
          /* - ERC20 Events - */
      
          /**
           * @notice EIP20 Transfer event
           */
          event Transfer(address indexed from, address indexed to, uint amount);
      
          /**
           * @notice EIP20 Approval event
           */
          event Approval(address indexed owner, address indexed spender, uint amount);
      
          /* - Extra Events - */
          /**
           * @notice Tokens minted event
           */
          event Mint(address to, uint256 amount);
      
          // Public functions
          function transfer(address to, uint256 value) external returns(bool);
          function transferFrom(address from, address to, uint256 value) external returns(bool);
          function balanceOf(address who) external view returns(uint256);
          function balanceOfUnderlying(address who) external view returns(uint256);
          function allowance(address owner_, address spender) external view returns(uint256);
          function approve(address spender, uint256 value) external returns (bool);
          function increaseAllowance(address spender, uint256 addedValue) external returns (bool);
          function decreaseAllowance(address spender, uint256 subtractedValue) external returns (bool);
          function maxScalingFactor() external view returns (uint256);
      
          /* - Governance Functions - */
          function getPriorVotes(address account, uint blockNumber) external view returns (uint256);
          function delegateBySig(address delegatee, uint nonce, uint expiry, uint8 v, bytes32 r, bytes32 s) external;
          function delegate(address delegatee) external;
          function delegates(address delegator) external view returns (address);
          function getCurrentVotes(address account) external view returns (uint256);
      
          /* - Permissioned/Governance functions - */
          function mint(address to, uint256 amount) external returns (bool);
          function rebase(uint256 epoch, uint256 indexDelta, bool positive) external returns (uint256);
          function _setRebaser(address rebaser_) external;
          function _setIncentivizer(address incentivizer_) external;
          function _setPendingGov(address pendingGov_) external;
          function _acceptGov() external;
      }
      
      
      contract YAMDelegationStorage {
          /**
           * @notice Implementation address for this contract
           */
          address public implementation;
      }
      
      contract YAMDelegatorInterface is YAMDelegationStorage {
          /**
           * @notice Emitted when implementation is changed
           */
          event NewImplementation(address oldImplementation, address newImplementation);
      
          /**
           * @notice Called by the gov to update the implementation of the delegator
           * @param implementation_ The address of the new implementation for delegation
           * @param allowResign Flag to indicate whether to call _resignImplementation on the old implementation
           * @param becomeImplementationData The encoded bytes data to be passed to _becomeImplementation
           */
          function _setImplementation(address implementation_, bool allowResign, bytes memory becomeImplementationData) public;
      }
      
      contract YAMDelegator is YAMTokenInterface, YAMDelegatorInterface {
          /**
           * @notice Construct a new YAM
           * @param name_ ERC-20 name of this token
           * @param symbol_ ERC-20 symbol of this token
           * @param decimals_ ERC-20 decimal precision of this token
           * @param initSupply_ Initial token amount
           * @param implementation_ The address of the implementation the contract delegates to
           * @param becomeImplementationData The encoded args for becomeImplementation
           */
          constructor(
              string memory name_,
              string memory symbol_,
              uint8 decimals_,
              uint256 initSupply_,
              address implementation_,
              bytes memory becomeImplementationData
          )
              public
          {
      
      
              // Creator of the contract is gov during initialization
              gov = msg.sender;
      
              // First delegate gets to initialize the delegator (i.e. storage contract)
              delegateTo(
                  implementation_,
                  abi.encodeWithSignature(
                      "initialize(string,string,uint8,address,uint256)",
                      name_,
                      symbol_,
                      decimals_,
                      msg.sender,
                      initSupply_
                  )
              );
      
              // New implementations always get set via the settor (post-initialize)
              _setImplementation(implementation_, false, becomeImplementationData);
      
          }
      
          /**
           * @notice Called by the gov to update the implementation of the delegator
           * @param implementation_ The address of the new implementation for delegation
           * @param allowResign Flag to indicate whether to call _resignImplementation on the old implementation
           * @param becomeImplementationData The encoded bytes data to be passed to _becomeImplementation
           */
          function _setImplementation(address implementation_, bool allowResign, bytes memory becomeImplementationData) public {
              require(msg.sender == gov, "YAMDelegator::_setImplementation: Caller must be gov");
      
              if (allowResign) {
                  delegateToImplementation(abi.encodeWithSignature("_resignImplementation()"));
              }
      
              address oldImplementation = implementation;
              implementation = implementation_;
      
              delegateToImplementation(abi.encodeWithSignature("_becomeImplementation(bytes)", becomeImplementationData));
      
              emit NewImplementation(oldImplementation, implementation);
          }
      
          /**
           * @notice Sender supplies assets into the market and receives cTokens in exchange
           * @dev Accrues interest whether or not the operation succeeds, unless reverted
           * @param mintAmount The amount of the underlying asset to supply
           * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
           */
          function mint(address to, uint256 mintAmount)
              external
              returns (bool)
          {
              to; mintAmount; // Shh
              delegateAndReturn();
          }
      
          /**
           * @notice Transfer `amount` tokens from `msg.sender` to `dst`
           * @param dst The address of the destination account
           * @param amount The number of tokens to transfer
           * @return Whether or not the transfer succeeded
           */
          function transfer(address dst, uint256 amount)
              external
              returns (bool)
          {
              dst; amount; // Shh
              delegateAndReturn();
          }
      
          /**
           * @notice Transfer `amount` tokens from `src` to `dst`
           * @param src The address of the source account
           * @param dst The address of the destination account
           * @param amount The number of tokens to transfer
           * @return Whether or not the transfer succeeded
           */
          function transferFrom(
              address src,
              address dst,
              uint256 amount
          )
              external
              returns (bool)
          {
              src; dst; amount; // Shh
              delegateAndReturn();
          }
      
          /**
           * @notice Approve `spender` to transfer up to `amount` from `src`
           * @dev This will overwrite the approval amount for `spender`
           *  and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve)
           * @param spender The address of the account which may transfer tokens
           * @param amount The number of tokens that are approved (-1 means infinite)
           * @return Whether or not the approval succeeded
           */
          function approve(
              address spender,
              uint256 amount
          )
              external
              returns (bool)
          {
              spender; amount; // Shh
              delegateAndReturn();
          }
      
          /**
           * @dev Increase the amount of tokens that an owner has allowed to a spender.
           * This method should be used instead of approve() to avoid the double approval vulnerability
           * described above.
           * @param spender The address which will spend the funds.
           * @param addedValue The amount of tokens to increase the allowance by.
           */
          function increaseAllowance(
              address spender,
              uint256 addedValue
          )
              external
              returns (bool)
          {
              spender; addedValue; // Shh
              delegateAndReturn();
          }
      
          function maxScalingFactor()
              external
              view
              returns (uint256)
          {
              delegateToViewAndReturn();
          }
      
          function rebase(
              uint256 epoch,
              uint256 indexDelta,
              bool positive
          )
              external
              returns (uint256)
          {
              epoch; indexDelta; positive;
              delegateAndReturn();
          }
      
          /**
           * @dev Decrease the amount of tokens that an owner has allowed to a spender.
           *
           * @param spender The address which will spend the funds.
           * @param subtractedValue The amount of tokens to decrease the allowance by.
           */
          function decreaseAllowance(
              address spender,
              uint256 subtractedValue
          )
              external
              returns (bool)
          {
              spender; subtractedValue; // Shh
              delegateAndReturn();
          }
      
          /**
           * @notice Get the current allowance from `owner` for `spender`
           * @param owner The address of the account which owns the tokens to be spent
           * @param spender The address of the account which may transfer tokens
           * @return The number of tokens allowed to be spent (-1 means infinite)
           */
          function allowance(
              address owner,
              address spender
          )
              external
              view
              returns (uint256)
          {
              owner; spender; // Shh
              delegateToViewAndReturn();
          }
      
          /**
           * @notice Get the current allowance from `owner` for `spender`
           * @param delegator The address of the account which has designated a delegate
           * @return Address of delegatee
           */
          function delegates(
              address delegator
          )
              external
              view
              returns (address)
          {
              delegator; // Shh
              delegateToViewAndReturn();
          }
      
          /**
           * @notice Get the token balance of the `owner`
           * @param owner The address of the account to query
           * @return The number of tokens owned by `owner`
           */
          function balanceOf(address owner)
              external
              view
              returns (uint256)
          {
              owner; // Shh
              delegateToViewAndReturn();
          }
      
          /**
           * @notice Currently unused. For future compatability
           * @param owner The address of the account to query
           * @return The number of underlying tokens owned by `owner`
           */
          function balanceOfUnderlying(address owner)
              external
              view
              returns (uint256)
          {
              owner; // Shh
              delegateToViewAndReturn();
          }
      
          /*** Gov Functions ***/
      
          /**
            * @notice Begins transfer of gov rights. The newPendingGov must call `_acceptGov` to finalize the transfer.
            * @dev Gov function to begin change of gov. The newPendingGov must call `_acceptGov` to finalize the transfer.
            * @param newPendingGov New pending gov.
            */
          function _setPendingGov(address newPendingGov)
              external
          {
              newPendingGov; // Shh
              delegateAndReturn();
          }
      
          function _setRebaser(address rebaser_)
              external
          {
              rebaser_; // Shh
              delegateAndReturn();
          }
      
          function _setIncentivizer(address incentivizer_)
              external
          {
              incentivizer_; // Shh
              delegateAndReturn();
          }
      
          /**
            * @notice Accepts transfer of gov rights. msg.sender must be pendingGov
            * @dev Gov function for pending gov to accept role and update gov
            * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
            */
          function _acceptGov()
              external
          {
              delegateAndReturn();
          }
      
      
          function getPriorVotes(address account, uint blockNumber)
              external
              view
              returns (uint256)
          {
              account; blockNumber;
              delegateToViewAndReturn();
          }
      
          function delegateBySig(
              address delegatee,
              uint nonce,
              uint expiry,
              uint8 v,
              bytes32 r,
              bytes32 s
          )
              external
          {
              delegatee; nonce; expiry; v; r; s;
              delegateAndReturn();
          }
      
          function delegate(address delegatee)
              external
          {
              delegatee;
              delegateAndReturn();
          }
      
          function getCurrentVotes(address account)
              external
              view
              returns (uint256)
          {
              account;
              delegateToViewAndReturn();
          }
      
          /**
           * @notice Internal method to delegate execution to another contract
           * @dev It returns to the external caller whatever the implementation returns or forwards reverts
           * @param callee The contract to delegatecall
           * @param data The raw data to delegatecall
           * @return The returned bytes from the delegatecall
           */
          function delegateTo(address callee, bytes memory data) internal returns (bytes memory) {
              (bool success, bytes memory returnData) = callee.delegatecall(data);
              assembly {
                  if eq(success, 0) {
                      revert(add(returnData, 0x20), returndatasize)
                  }
              }
              return returnData;
          }
      
          /**
           * @notice Delegates execution to the implementation contract
           * @dev It returns to the external caller whatever the implementation returns or forwards reverts
           * @param data The raw data to delegatecall
           * @return The returned bytes from the delegatecall
           */
          function delegateToImplementation(bytes memory data) public returns (bytes memory) {
              return delegateTo(implementation, data);
          }
      
          /**
           * @notice Delegates execution to an implementation contract
           * @dev It returns to the external caller whatever the implementation returns or forwards reverts
           *  There are an additional 2 prefix uints from the wrapper returndata, which we ignore since we make an extra hop.
           * @param data The raw data to delegatecall
           * @return The returned bytes from the delegatecall
           */
          function delegateToViewImplementation(bytes memory data) public view returns (bytes memory) {
              (bool success, bytes memory returnData) = address(this).staticcall(abi.encodeWithSignature("delegateToImplementation(bytes)", data));
              assembly {
                  if eq(success, 0) {
                      revert(add(returnData, 0x20), returndatasize)
                  }
              }
              return abi.decode(returnData, (bytes));
          }
      
          function delegateToViewAndReturn() private view returns (bytes memory) {
              (bool success, ) = address(this).staticcall(abi.encodeWithSignature("delegateToImplementation(bytes)", msg.data));
      
              assembly {
                  let free_mem_ptr := mload(0x40)
                  returndatacopy(free_mem_ptr, 0, returndatasize)
      
                  switch success
                  case 0 { revert(free_mem_ptr, returndatasize) }
                  default { return(add(free_mem_ptr, 0x40), returndatasize) }
              }
          }
      
          function delegateAndReturn() private returns (bytes memory) {
              (bool success, ) = implementation.delegatecall(msg.data);
      
              assembly {
                  let free_mem_ptr := mload(0x40)
                  returndatacopy(free_mem_ptr, 0, returndatasize)
      
                  switch success
                  case 0 { revert(free_mem_ptr, returndatasize) }
                  default { return(free_mem_ptr, returndatasize) }
              }
          }
      
          /**
           * @notice Delegates execution to an implementation contract
           * @dev It returns to the external caller whatever the implementation returns or forwards reverts
           */
          function () external payable {
              require(msg.value == 0,"YAMDelegator:fallback: cannot send value to fallback");
      
              // delegate all other functions to current implementation
              delegateAndReturn();
          }
      }

      File 3 of 3: YAMDelegate
      pragma solidity 0.5.17;
      
      
      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.
           */
          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.
           */
          function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
              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.
           */
          function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
              require(b != 0, errorMessage);
              return a % b;
          }
      }
      
      
      contract YAMTokenStorage {
      
          using SafeMath for uint256;
      
          /**
           * @dev Guard variable for re-entrancy checks. Not currently used
           */
          bool internal _notEntered;
      
          /**
           * @notice EIP-20 token name for this token
           */
          string public name;
      
          /**
           * @notice EIP-20 token symbol for this token
           */
          string public symbol;
      
          /**
           * @notice EIP-20 token decimals for this token
           */
          uint8 public decimals;
      
          /**
           * @notice Governor for this contract
           */
          address public gov;
      
          /**
           * @notice Pending governance for this contract
           */
          address public pendingGov;
      
          /**
           * @notice Approved rebaser for this contract
           */
          address public rebaser;
      
          /**
           * @notice Reserve address of YAM protocol
           */
          address public incentivizer;
      
          /**
           * @notice Total supply of YAMs
           */
          uint256 public totalSupply;
      
          /**
           * @notice Internal decimals used to handle scaling factor
           */
          uint256 public constant internalDecimals = 10**24;
      
          /**
           * @notice Used for percentage maths
           */
          uint256 public constant BASE = 10**18;
      
          /**
           * @notice Scaling factor that adjusts everyone's balances
           */
          uint256 public yamsScalingFactor;
      
          mapping (address => uint256) internal _yamBalances;
      
          mapping (address => mapping (address => uint256)) internal _allowedFragments;
      
          uint256 public initSupply;
      
      }
      
      
      contract YAMGovernanceStorage {
          /// @notice A record of each accounts delegate
          mapping (address => address) internal _delegates;
      
          /// @notice A checkpoint for marking number of votes from a given block
          struct Checkpoint {
              uint32 fromBlock;
              uint256 votes;
          }
      
          /// @notice A record of votes checkpoints for each account, by index
          mapping (address => mapping (uint32 => Checkpoint)) public checkpoints;
      
          /// @notice The number of checkpoints for each account
          mapping (address => uint32) public numCheckpoints;
      
          /// @notice The EIP-712 typehash for the contract's domain
          bytes32 public constant DOMAIN_TYPEHASH = keccak256("EIP712Domain(string name,uint256 chainId,address verifyingContract)");
      
          /// @notice The EIP-712 typehash for the delegation struct used by the contract
          bytes32 public constant DELEGATION_TYPEHASH = keccak256("Delegation(address delegatee,uint256 nonce,uint256 expiry)");
      
          /// @notice A record of states for signing / validating signatures
          mapping (address => uint) public nonces;
      }
      
      
      contract YAMTokenInterface is YAMTokenStorage, YAMGovernanceStorage {
      
          /// @notice An event thats emitted when an account changes its delegate
          event DelegateChanged(address indexed delegator, address indexed fromDelegate, address indexed toDelegate);
      
          /// @notice An event thats emitted when a delegate account's vote balance changes
          event DelegateVotesChanged(address indexed delegate, uint previousBalance, uint newBalance);
      
          /**
           * @notice Event emitted when tokens are rebased
           */
          event Rebase(uint256 epoch, uint256 prevYamsScalingFactor, uint256 newYamsScalingFactor);
      
          /*** Gov Events ***/
      
          /**
           * @notice Event emitted when pendingGov is changed
           */
          event NewPendingGov(address oldPendingGov, address newPendingGov);
      
          /**
           * @notice Event emitted when gov is changed
           */
          event NewGov(address oldGov, address newGov);
      
          /**
           * @notice Sets the rebaser contract
           */
          event NewRebaser(address oldRebaser, address newRebaser);
      
          /**
           * @notice Sets the incentivizer contract
           */
          event NewIncentivizer(address oldIncentivizer, address newIncentivizer);
      
          /* - ERC20 Events - */
      
          /**
           * @notice EIP20 Transfer event
           */
          event Transfer(address indexed from, address indexed to, uint amount);
      
          /**
           * @notice EIP20 Approval event
           */
          event Approval(address indexed owner, address indexed spender, uint amount);
      
          /* - Extra Events - */
          /**
           * @notice Tokens minted event
           */
          event Mint(address to, uint256 amount);
      
          // Public functions
          function transfer(address to, uint256 value) external returns(bool);
          function transferFrom(address from, address to, uint256 value) external returns(bool);
          function balanceOf(address who) external view returns(uint256);
          function balanceOfUnderlying(address who) external view returns(uint256);
          function allowance(address owner_, address spender) external view returns(uint256);
          function approve(address spender, uint256 value) external returns (bool);
          function increaseAllowance(address spender, uint256 addedValue) external returns (bool);
          function decreaseAllowance(address spender, uint256 subtractedValue) external returns (bool);
          function maxScalingFactor() external view returns (uint256);
      
          /* - Governance Functions - */
          function getPriorVotes(address account, uint blockNumber) external view returns (uint256);
          function delegateBySig(address delegatee, uint nonce, uint expiry, uint8 v, bytes32 r, bytes32 s) external;
          function delegate(address delegatee) external;
          function delegates(address delegator) external view returns (address);
          function getCurrentVotes(address account) external view returns (uint256);
      
          /* - Permissioned/Governance functions - */
          function mint(address to, uint256 amount) external returns (bool);
          function rebase(uint256 epoch, uint256 indexDelta, bool positive) external returns (uint256);
          function _setRebaser(address rebaser_) external;
          function _setIncentivizer(address incentivizer_) external;
          function _setPendingGov(address pendingGov_) external;
          function _acceptGov() external;
      }
      
      
      contract YAMGovernanceToken is YAMTokenInterface {
      
            /// @notice An event thats emitted when an account changes its delegate
          event DelegateChanged(address indexed delegator, address indexed fromDelegate, address indexed toDelegate);
      
          /// @notice An event thats emitted when a delegate account's vote balance changes
          event DelegateVotesChanged(address indexed delegate, uint previousBalance, uint newBalance);
      
          /**
           * @notice Delegate votes from `msg.sender` to `delegatee`
           * @param delegator The address to get delegatee for
           */
          function delegates(address delegator)
              external
              view
              returns (address)
          {
              return _delegates[delegator];
          }
      
         /**
          * @notice Delegate votes from `msg.sender` to `delegatee`
          * @param delegatee The address to delegate votes to
          */
          function delegate(address delegatee) external {
              return _delegate(msg.sender, delegatee);
          }
      
          /**
           * @notice Delegates votes from signatory to `delegatee`
           * @param delegatee The address to delegate votes to
           * @param nonce The contract state required to match the signature
           * @param expiry The time at which to expire the signature
           * @param v The recovery byte of the signature
           * @param r Half of the ECDSA signature pair
           * @param s Half of the ECDSA signature pair
           */
          function delegateBySig(
              address delegatee,
              uint nonce,
              uint expiry,
              uint8 v,
              bytes32 r,
              bytes32 s
          )
              external
          {
              bytes32 domainSeparator = keccak256(
                  abi.encode(
                      DOMAIN_TYPEHASH,
                      keccak256(bytes(name)),
                      getChainId(),
                      address(this)
                  )
              );
      
              bytes32 structHash = keccak256(
                  abi.encode(
                      DELEGATION_TYPEHASH,
                      delegatee,
                      nonce,
                      expiry
                  )
              );
      
              bytes32 digest = keccak256(
                  abi.encodePacked(
                      "\x19\x01",
                      domainSeparator,
                      structHash
                  )
              );
      
              address signatory = ecrecover(digest, v, r, s);
              require(signatory != address(0), "YAM::delegateBySig: invalid signature");
              require(nonce == nonces[signatory]++, "YAM::delegateBySig: invalid nonce");
              require(now <= expiry, "YAM::delegateBySig: signature expired");
              return _delegate(signatory, delegatee);
          }
      
          /**
           * @notice Gets the current votes balance for `account`
           * @param account The address to get votes balance
           * @return The number of current votes for `account`
           */
          function getCurrentVotes(address account)
              external
              view
              returns (uint256)
          {
              uint32 nCheckpoints = numCheckpoints[account];
              return nCheckpoints > 0 ? checkpoints[account][nCheckpoints - 1].votes : 0;
          }
      
          /**
           * @notice Determine the prior number of votes for an account as of a block number
           * @dev Block number must be a finalized block or else this function will revert to prevent misinformation.
           * @param account The address of the account to check
           * @param blockNumber The block number to get the vote balance at
           * @return The number of votes the account had as of the given block
           */
          function getPriorVotes(address account, uint blockNumber)
              external
              view
              returns (uint256)
          {
              require(blockNumber < block.number, "YAM::getPriorVotes: not yet determined");
      
              uint32 nCheckpoints = numCheckpoints[account];
              if (nCheckpoints == 0) {
                  return 0;
              }
      
              // First check most recent balance
              if (checkpoints[account][nCheckpoints - 1].fromBlock <= blockNumber) {
                  return checkpoints[account][nCheckpoints - 1].votes;
              }
      
              // Next check implicit zero balance
              if (checkpoints[account][0].fromBlock > blockNumber) {
                  return 0;
              }
      
              uint32 lower = 0;
              uint32 upper = nCheckpoints - 1;
              while (upper > lower) {
                  uint32 center = upper - (upper - lower) / 2; // ceil, avoiding overflow
                  Checkpoint memory cp = checkpoints[account][center];
                  if (cp.fromBlock == blockNumber) {
                      return cp.votes;
                  } else if (cp.fromBlock < blockNumber) {
                      lower = center;
                  } else {
                      upper = center - 1;
                  }
              }
              return checkpoints[account][lower].votes;
          }
      
          function _delegate(address delegator, address delegatee)
              internal
          {
              address currentDelegate = _delegates[delegator];
              uint256 delegatorBalance = _yamBalances[delegator]; // balance of underlying YAMs (not scaled);
              _delegates[delegator] = delegatee;
      
              emit DelegateChanged(delegator, currentDelegate, delegatee);
      
              _moveDelegates(currentDelegate, delegatee, delegatorBalance);
          }
      
          function _moveDelegates(address srcRep, address dstRep, uint256 amount) internal {
              if (srcRep != dstRep && amount > 0) {
                  if (srcRep != address(0)) {
                      // decrease old representative
                      uint32 srcRepNum = numCheckpoints[srcRep];
                      uint256 srcRepOld = srcRepNum > 0 ? checkpoints[srcRep][srcRepNum - 1].votes : 0;
                      uint256 srcRepNew = srcRepOld.sub(amount);
                      _writeCheckpoint(srcRep, srcRepNum, srcRepOld, srcRepNew);
                  }
      
                  if (dstRep != address(0)) {
                      // increase new representative
                      uint32 dstRepNum = numCheckpoints[dstRep];
                      uint256 dstRepOld = dstRepNum > 0 ? checkpoints[dstRep][dstRepNum - 1].votes : 0;
                      uint256 dstRepNew = dstRepOld.add(amount);
                      _writeCheckpoint(dstRep, dstRepNum, dstRepOld, dstRepNew);
                  }
              }
          }
      
          function _writeCheckpoint(
              address delegatee,
              uint32 nCheckpoints,
              uint256 oldVotes,
              uint256 newVotes
          )
              internal
          {
              uint32 blockNumber = safe32(block.number, "YAM::_writeCheckpoint: block number exceeds 32 bits");
      
              if (nCheckpoints > 0 && checkpoints[delegatee][nCheckpoints - 1].fromBlock == blockNumber) {
                  checkpoints[delegatee][nCheckpoints - 1].votes = newVotes;
              } else {
                  checkpoints[delegatee][nCheckpoints] = Checkpoint(blockNumber, newVotes);
                  numCheckpoints[delegatee] = nCheckpoints + 1;
              }
      
              emit DelegateVotesChanged(delegatee, oldVotes, newVotes);
          }
      
          function safe32(uint n, string memory errorMessage) internal pure returns (uint32) {
              require(n < 2**32, errorMessage);
              return uint32(n);
          }
      
          function getChainId() internal pure returns (uint) {
              uint256 chainId;
              assembly { chainId := chainid() }
              return chainId;
          }
      }
      
      contract YAMToken is YAMGovernanceToken {
          // Modifiers
          modifier onlyGov() {
              require(msg.sender == gov);
              _;
          }
      
          modifier onlyRebaser() {
              require(msg.sender == rebaser);
              _;
          }
      
          modifier onlyMinter() {
              require(msg.sender == rebaser || msg.sender == incentivizer || msg.sender == gov, "not minter");
              _;
          }
      
          modifier validRecipient(address to) {
              require(to != address(0x0));
              require(to != address(this));
              _;
          }
      
          function initialize(
              string memory name_,
              string memory symbol_,
              uint8 decimals_
          )
              public
          {
              require(yamsScalingFactor == 0, "already initialized");
              name = name_;
              symbol = symbol_;
              decimals = decimals_;
          }
      
      
          /**
          * @notice Computes the current max scaling factor
          */
          function maxScalingFactor()
              external
              view
              returns (uint256)
          {
              return _maxScalingFactor();
          }
      
          function _maxScalingFactor()
              internal
              view
              returns (uint256)
          {
              // scaling factor can only go up to 2**256-1 = initSupply * yamsScalingFactor
              // this is used to check if yamsScalingFactor will be too high to compute balances when rebasing.
              return uint256(-1) / initSupply;
          }
      
          /**
          * @notice Mints new tokens, increasing totalSupply, initSupply, and a users balance.
          * @dev Limited to onlyMinter modifier
          */
          function mint(address to, uint256 amount)
              external
              onlyMinter
              returns (bool)
          {
              _mint(to, amount);
              return true;
          }
      
          function _mint(address to, uint256 amount)
              internal
          {
            // increase totalSupply
            totalSupply = totalSupply.add(amount);
      
            // get underlying value
            uint256 yamValue = amount.mul(internalDecimals).div(yamsScalingFactor);
      
            // increase initSupply
            initSupply = initSupply.add(yamValue);
      
            // make sure the mint didnt push maxScalingFactor too low
            require(yamsScalingFactor <= _maxScalingFactor(), "max scaling factor too low");
      
            // add balance
            _yamBalances[to] = _yamBalances[to].add(yamValue);
      
            // add delegates to the minter
            _moveDelegates(address(0), _delegates[to], yamValue);
            emit Mint(to, amount);
          }
      
          /* - ERC20 functionality - */
      
          /**
          * @dev Transfer tokens to a specified address.
          * @param to The address to transfer to.
          * @param value The amount to be transferred.
          * @return True on success, false otherwise.
          */
          function transfer(address to, uint256 value)
              external
              validRecipient(to)
              returns (bool)
          {
              // underlying balance is stored in yams, so divide by current scaling factor
      
              // note, this means as scaling factor grows, dust will be untransferrable.
              // minimum transfer value == yamsScalingFactor / 1e24;
      
              // get amount in underlying
              uint256 yamValue = value.mul(internalDecimals).div(yamsScalingFactor);
      
              // sub from balance of sender
              _yamBalances[msg.sender] = _yamBalances[msg.sender].sub(yamValue);
      
              // add to balance of receiver
              _yamBalances[to] = _yamBalances[to].add(yamValue);
              emit Transfer(msg.sender, to, value);
      
              _moveDelegates(_delegates[msg.sender], _delegates[to], yamValue);
              return true;
          }
      
          /**
          * @dev Transfer tokens from one address to another.
          * @param from The address you want to send tokens from.
          * @param to The address you want to transfer to.
          * @param value The amount of tokens to be transferred.
          */
          function transferFrom(address from, address to, uint256 value)
              external
              validRecipient(to)
              returns (bool)
          {
              // decrease allowance
              _allowedFragments[from][msg.sender] = _allowedFragments[from][msg.sender].sub(value);
      
              // get value in yams
              uint256 yamValue = value.mul(internalDecimals).div(yamsScalingFactor);
      
              // sub from from
              _yamBalances[from] = _yamBalances[from].sub(yamValue);
              _yamBalances[to] = _yamBalances[to].add(yamValue);
              emit Transfer(from, to, value);
      
              _moveDelegates(_delegates[from], _delegates[to], yamValue);
              return true;
          }
      
          /**
          * @param who The address to query.
          * @return The balance of the specified address.
          */
          function balanceOf(address who)
            external
            view
            returns (uint256)
          {
            return _yamBalances[who].mul(yamsScalingFactor).div(internalDecimals);
          }
      
          /** @notice Currently returns the internal storage amount
          * @param who The address to query.
          * @return The underlying balance of the specified address.
          */
          function balanceOfUnderlying(address who)
            external
            view
            returns (uint256)
          {
            return _yamBalances[who];
          }
      
          /**
           * @dev Function to check the amount of tokens that an owner has allowed to a spender.
           * @param owner_ The address which owns the funds.
           * @param spender The address which will spend the funds.
           * @return The number of tokens still available for the spender.
           */
          function allowance(address owner_, address spender)
              external
              view
              returns (uint256)
          {
              return _allowedFragments[owner_][spender];
          }
      
          /**
           * @dev Approve the passed address to spend the specified amount of tokens on behalf of
           * msg.sender. This method is included for ERC20 compatibility.
           * increaseAllowance and decreaseAllowance should be used instead.
           * Changing an allowance with this method brings the risk that someone may transfer both
           * the old and the new allowance - if they are both greater than zero - if a transfer
           * transaction is mined before the later approve() call is mined.
           *
           * @param spender The address which will spend the funds.
           * @param value The amount of tokens to be spent.
           */
          function approve(address spender, uint256 value)
              external
              returns (bool)
          {
              _allowedFragments[msg.sender][spender] = value;
              emit Approval(msg.sender, spender, value);
              return true;
          }
      
          /**
           * @dev Increase the amount of tokens that an owner has allowed to a spender.
           * This method should be used instead of approve() to avoid the double approval vulnerability
           * described above.
           * @param spender The address which will spend the funds.
           * @param addedValue The amount of tokens to increase the allowance by.
           */
          function increaseAllowance(address spender, uint256 addedValue)
              external
              returns (bool)
          {
              _allowedFragments[msg.sender][spender] =
                  _allowedFragments[msg.sender][spender].add(addedValue);
              emit Approval(msg.sender, spender, _allowedFragments[msg.sender][spender]);
              return true;
          }
      
          /**
           * @dev Decrease the amount of tokens that an owner has allowed to a spender.
           *
           * @param spender The address which will spend the funds.
           * @param subtractedValue The amount of tokens to decrease the allowance by.
           */
          function decreaseAllowance(address spender, uint256 subtractedValue)
              external
              returns (bool)
          {
              uint256 oldValue = _allowedFragments[msg.sender][spender];
              if (subtractedValue >= oldValue) {
                  _allowedFragments[msg.sender][spender] = 0;
              } else {
                  _allowedFragments[msg.sender][spender] = oldValue.sub(subtractedValue);
              }
              emit Approval(msg.sender, spender, _allowedFragments[msg.sender][spender]);
              return true;
          }
      
          /* - Governance Functions - */
      
          /** @notice sets the rebaser
           * @param rebaser_ The address of the rebaser contract to use for authentication.
           */
          function _setRebaser(address rebaser_)
              external
              onlyGov
          {
              address oldRebaser = rebaser;
              rebaser = rebaser_;
              emit NewRebaser(oldRebaser, rebaser_);
          }
      
          /** @notice sets the incentivizer
           * @param incentivizer_ The address of the rebaser contract to use for authentication.
           */
          function _setIncentivizer(address incentivizer_)
              external
              onlyGov
          {
              address oldIncentivizer = incentivizer;
              incentivizer = incentivizer_;
              emit NewIncentivizer(oldIncentivizer, incentivizer_);
          }
      
          /** @notice sets the pendingGov
           * @param pendingGov_ The address of the rebaser contract to use for authentication.
           */
          function _setPendingGov(address pendingGov_)
              external
              onlyGov
          {
              address oldPendingGov = pendingGov;
              pendingGov = pendingGov_;
              emit NewPendingGov(oldPendingGov, pendingGov_);
          }
      
          /** @notice lets msg.sender accept governance
           *
           */
          function _acceptGov()
              external
          {
              require(msg.sender == pendingGov, "!pending");
              address oldGov = gov;
              gov = pendingGov;
              pendingGov = address(0);
              emit NewGov(oldGov, gov);
          }
      
          /* - Extras - */
      
          /**
          * @notice Initiates a new rebase operation, provided the minimum time period has elapsed.
          *
          * @dev The supply adjustment equals (totalSupply * DeviationFromTargetRate) / rebaseLag
          *      Where DeviationFromTargetRate is (MarketOracleRate - targetRate) / targetRate
          *      and targetRate is CpiOracleRate / baseCpi
          */
          function rebase(
              uint256 epoch,
              uint256 indexDelta,
              bool positive
          )
              external
              onlyRebaser
              returns (uint256)
          {
              if (indexDelta == 0) {
                emit Rebase(epoch, yamsScalingFactor, yamsScalingFactor);
                return totalSupply;
              }
      
              uint256 prevYamsScalingFactor = yamsScalingFactor;
      
              if (!positive) {
                 yamsScalingFactor = yamsScalingFactor.mul(BASE.sub(indexDelta)).div(BASE);
              } else {
                  uint256 newScalingFactor = yamsScalingFactor.mul(BASE.add(indexDelta)).div(BASE);
                  if (newScalingFactor < _maxScalingFactor()) {
                      yamsScalingFactor = newScalingFactor;
                  } else {
                    yamsScalingFactor = _maxScalingFactor();
                  }
              }
      
              totalSupply = initSupply.mul(yamsScalingFactor);
              emit Rebase(epoch, prevYamsScalingFactor, yamsScalingFactor);
              return totalSupply;
          }
      }
      
      contract YAM is YAMToken {
          /**
           * @notice Initialize the new money market
           * @param name_ ERC-20 name of this token
           * @param symbol_ ERC-20 symbol of this token
           * @param decimals_ ERC-20 decimal precision of this token
           */
          function initialize(
              string memory name_,
              string memory symbol_,
              uint8 decimals_,
              address initial_owner,
              uint256 initSupply_
          )
              public
          {
              require(initSupply_ > 0, "0 init supply");
      
              super.initialize(name_, symbol_, decimals_);
      
              initSupply = initSupply_.mul(10**24/ (BASE));
              totalSupply = initSupply_;
              yamsScalingFactor = BASE;
              _yamBalances[initial_owner] = initSupply_.mul(10**24 / (BASE));
      
              // owner renounces ownership after deployment as they need to set
              // rebaser and incentivizer
              // gov = gov_;
          }
      }
      
      contract YAMDelegationStorage {
          /**
           * @notice Implementation address for this contract
           */
          address public implementation;
      }
      
      contract YAMDelegateInterface is YAMDelegationStorage {
          /**
           * @notice Called by the delegator on a delegate to initialize it for duty
           * @dev Should revert if any issues arise which make it unfit for delegation
           * @param data The encoded bytes data for any initialization
           */
          function _becomeImplementation(bytes memory data) public;
      
          /**
           * @notice Called by the delegator on a delegate to forfeit its responsibility
           */
          function _resignImplementation() public;
      }
      
      contract YAMDelegate is YAM, YAMDelegateInterface {
          /**
           * @notice Construct an empty delegate
           */
          constructor() public {}
      
          /**
           * @notice Called by the delegator on a delegate to initialize it for duty
           * @param data The encoded bytes data for any initialization
           */
          function _becomeImplementation(bytes memory data) public {
              // Shh -- currently unused
              data;
      
              // Shh -- we don't ever want this hook to be marked pure
              if (false) {
                  implementation = address(0);
              }
      
              require(msg.sender == gov, "only the gov may call _becomeImplementation");
          }
      
          /**
           * @notice Called by the delegator on a delegate to forfeit its responsibility
           */
          function _resignImplementation() public {
              // Shh -- we don't ever want this hook to be marked pure
              if (false) {
                  implementation = address(0);
              }
      
              require(msg.sender == gov, "only the gov may call _resignImplementation");
          }
      }