ETH Price: $1,837.49 (-0.55%)

Transaction Decoder

Block:
12379853 at May-06-2021 09:15:03 AM +UTC
Transaction Fee:
0.01580625051247375 ETH $29.04
Gas Used:
351,250 Gas / 45.000001459 Gwei

Emitted Events:

376 TON.Approval( owner=[Sender] 0xffdcabffb9ec425fd0b469ef626c844cb68670e8, spender=WTON, value=6053156211600000000000 )
377 WTON.Transfer( from=0x0000000000000000000000000000000000000000, to=[Sender] 0xffdcabffb9ec425fd0b469ef626c844cb68670e8, value=6053156211600000000000000000000 )
378 TON.Transfer( from=[Sender] 0xffdcabffb9ec425fd0b469ef626c844cb68670e8, to=WTON, value=6053156211600000000000 )
379 TON.Approval( owner=[Sender] 0xffdcabffb9ec425fd0b469ef626c844cb68670e8, spender=WTON, value=0 )
380 WTON.Approval( owner=[Sender] 0xffdcabffb9ec425fd0b469ef626c844cb68670e8, spender=DepositManager, value=6053156211600000000000000000000 )
381 WTON.Transfer( from=[Sender] 0xffdcabffb9ec425fd0b469ef626c844cb68670e8, to=DepositManager, value=6053156211600000000000000000000 )
382 WTON.Approval( owner=[Sender] 0xffdcabffb9ec425fd0b469ef626c844cb68670e8, spender=DepositManager, value=0 )
383 DepositManager.Deposited( layer2=0xBC8896Ebb2E3939B1849298Ef8da59E09946cF66, depositor=[Sender] 0xffdcabffb9ec425fd0b469ef626c844cb68670e8, amount=6053156211600000000000000000000 )
384 AutoRefactorCoinage.Transfer( from=0x0000000000000000000000000000000000000000, to=0xBC8896Ebb2E3939B1849298Ef8da59E09946cF66, value=1704541849415703076217556215420391 )
385 AutoRefactorCoinage.Transfer( from=0x0000000000000000000000000000000000000000, to=[Sender] 0xffdcabffb9ec425fd0b469ef626c844cb68670e8, value=6053156211599999999999999999999 )
386 PowerTON.PowerIncreased( account=[Sender] 0xffdcabffb9ec425fd0b469ef626c844cb68670e8, amount=6053156211600000000000000000000 )

Account State Difference:

  Address   Before After State Difference Code
33.121775634910529584 Eth33.137581885423003334 Eth0.01580625051247375
0x2be5e8c1...a9b3433C5
0x565865C1...867204B1a
0x56E465f6...7195CEe43
0x6FC20Ca2...525f7AeEf
0xc4A11aaf...84F15bff2
0xd86d8950...CE249E1CF
0xFfdcabff...CB68670E8
1.01152629 Eth
Nonce: 368
0.99572003948752625 Eth
Nonce: 369
0.01580625051247375

Execution Trace

TON.approveAndCall( spender=0xc4A11aaf6ea915Ed7Ac194161d2fC9384F15bff2, amount=6053156211600000000000, data=0x00000000000000000000000056E465F654393FA48F007ED7346105C7195CEE43000000000000000000000000BC8896EBB2E3939B1849298EF8DA59E09946CF66 ) => ( True )
  • WTON.supportsInterface( interfaceId=System.Byte[] ) => ( True )
  • WTON.supportsInterface( interfaceId=System.Byte[] ) => ( False )
  • WTON.supportsInterface( interfaceId=System.Byte[] ) => ( True )
  • WTON.onApprove( owner=0xFfdcabffB9EC425FD0B469eF626c844CB68670E8, spender=0xc4A11aaf6ea915Ed7Ac194161d2fC9384F15bff2, tonAmount=6053156211600000000000, data=0x00000000000000000000000056E465F654393FA48F007ED7346105C7195CEE43000000000000000000000000BC8896EBB2E3939B1849298EF8DA59E09946CF66 ) => ( True )
    • TON.transferFrom( sender=0xFfdcabffB9EC425FD0B469eF626c844CB68670E8, recipient=0xc4A11aaf6ea915Ed7Ac194161d2fC9384F15bff2, amount=6053156211600000000000 ) => ( True )
    • DepositManager.supportsInterface( interfaceId=System.Byte[] ) => ( True )
    • DepositManager.supportsInterface( interfaceId=System.Byte[] ) => ( False )
    • DepositManager.supportsInterface( interfaceId=System.Byte[] ) => ( True )
    • DepositManager.onApprove( owner=0xFfdcabffB9EC425FD0B469eF626c844CB68670E8, spender=0x56E465f654393fa48f007Ed7346105c7195CEe43, amount=6053156211600000000000000000000, data=0x000000000000000000000000BC8896EBB2E3939B1849298EF8DA59E09946CF66 ) => ( True )
      • Layer2Registry.layer2s( layer2=0xBC8896Ebb2E3939B1849298Ef8da59E09946cF66 ) => ( True )
      • WTON.transferFrom( sender=0xFfdcabffB9EC425FD0B469eF626c844CB68670E8, recipient=0x56E465f654393fa48f007Ed7346105c7195CEe43, amount=6053156211600000000000000000000 ) => ( True )
      • SeigManager.onDeposit( layer2=0xBC8896Ebb2E3939B1849298Ef8da59E09946cF66, account=0xFfdcabffB9EC425FD0B469eF626c844CB68670E8, amount=6053156211600000000000000000000 ) => ( True )
        • 0xbc8896ebb2e3939b1849298ef8da59e09946cf66.STATICCALL( )
        • AutoRefactorCoinage.mint( account=0xBC8896Ebb2E3939B1849298Ef8da59E09946cF66, amount=6053156211600000000000000000000 ) => ( True )
        • AutoRefactorCoinage.mint( account=0xFfdcabffB9EC425FD0B469eF626c844CB68670E8, amount=6053156211600000000000000000000 ) => ( True )
        • PowerTON.onDeposit( layer2=0xBC8896Ebb2E3939B1849298Ef8da59E09946cF66, account=0xFfdcabffB9EC425FD0B469eF626c844CB68670E8, amount=6053156211600000000000000000000 )
          File 1 of 8: TON
          // File: openzeppelin-solidity/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-solidity/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 {
                  address msgSender = _msgSender();
                  _owner = msgSender;
                  emit OwnershipTransferred(address(0), msgSender);
              }
          
              /**
               * @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-solidity/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);
          
              /**
               * @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-solidity/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-solidity/contracts/token/ERC20/ERC20.sol
          
          pragma solidity ^0.5.0;
          
          
          
          
          /**
           * @dev Implementation of the {IERC20} interface.
           *
           * This implementation is agnostic to the way tokens are created. This means
           * that a supply mechanism has to be added in a derived contract using {_mint}.
           * For a generic mechanism see {ERC20Mintable}.
           *
           * TIP: For a detailed writeup see our guide
           * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How
           * to implement supply mechanisms].
           *
           * We have followed general OpenZeppelin guidelines: functions revert instead
           * of returning `false` on failure. This behavior is nonetheless conventional
           * and does not conflict with the expectations of ERC20 applications.
           *
           * Additionally, an {Approval} event is emitted on calls to {transferFrom}.
           * This allows applications to reconstruct the allowance for all accounts just
           * by listening to said events. Other implementations of the EIP may not emit
           * these events, as it isn't required by the specification.
           *
           * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}
           * functions have been added to mitigate the well-known issues around setting
           * allowances. See {IERC20-approve}.
           */
          contract ERC20 is Context, IERC20 {
              using SafeMath for uint256;
          
              mapping (address => uint256) private _balances;
          
              mapping (address => mapping (address => uint256)) private _allowances;
          
              uint256 private _totalSupply;
          
              /**
               * @dev See {IERC20-totalSupply}.
               */
              function totalSupply() public view returns (uint256) {
                  return _totalSupply;
              }
          
              /**
               * @dev See {IERC20-balanceOf}.
               */
              function balanceOf(address account) public view returns (uint256) {
                  return _balances[account];
              }
          
              /**
               * @dev See {IERC20-transfer}.
               *
               * Requirements:
               *
               * - `recipient` cannot be the zero address.
               * - the caller must have a balance of at least `amount`.
               */
              function transfer(address recipient, uint256 amount) public returns (bool) {
                  _transfer(_msgSender(), recipient, amount);
                  return true;
              }
          
              /**
               * @dev See {IERC20-allowance}.
               */
              function allowance(address owner, address spender) public view returns (uint256) {
                  return _allowances[owner][spender];
              }
          
              /**
               * @dev See {IERC20-approve}.
               *
               * Requirements:
               *
               * - `spender` cannot be the zero address.
               */
              function approve(address spender, uint256 amount) public returns (bool) {
                  _approve(_msgSender(), spender, amount);
                  return true;
              }
          
              /**
               * @dev See {IERC20-transferFrom}.
               *
               * Emits an {Approval} event indicating the updated allowance. This is not
               * required by the EIP. See the note at the beginning of {ERC20};
               *
               * Requirements:
               * - `sender` and `recipient` cannot be the zero address.
               * - `sender` must have a balance of at least `amount`.
               * - the caller must have allowance for `sender`'s tokens of at least
               * `amount`.
               */
              function transferFrom(address sender, address recipient, uint256 amount) public returns (bool) {
                  _transfer(sender, recipient, amount);
                  _approve(sender, _msgSender(), _allowances[sender][_msgSender()].sub(amount, "ERC20: transfer amount exceeds allowance"));
                  return true;
              }
          
              /**
               * @dev Atomically increases the allowance granted to `spender` by the caller.
               *
               * This is an alternative to {approve} that can be used as a mitigation for
               * problems described in {IERC20-approve}.
               *
               * Emits an {Approval} event indicating the updated allowance.
               *
               * Requirements:
               *
               * - `spender` cannot be the zero address.
               */
              function increaseAllowance(address spender, uint256 addedValue) public returns (bool) {
                  _approve(_msgSender(), spender, _allowances[_msgSender()][spender].add(addedValue));
                  return true;
              }
          
              /**
               * @dev Atomically decreases the allowance granted to `spender` by the caller.
               *
               * This is an alternative to {approve} that can be used as a mitigation for
               * problems described in {IERC20-approve}.
               *
               * Emits an {Approval} event indicating the updated allowance.
               *
               * Requirements:
               *
               * - `spender` cannot be the zero address.
               * - `spender` must have allowance for the caller of at least
               * `subtractedValue`.
               */
              function decreaseAllowance(address spender, uint256 subtractedValue) public returns (bool) {
                  _approve(_msgSender(), spender, _allowances[_msgSender()][spender].sub(subtractedValue, "ERC20: decreased allowance below zero"));
                  return true;
              }
          
              /**
               * @dev Moves tokens `amount` from `sender` to `recipient`.
               *
               * This is internal function is equivalent to {transfer}, and can be used to
               * e.g. implement automatic token fees, slashing mechanisms, etc.
               *
               * Emits a {Transfer} event.
               *
               * Requirements:
               *
               * - `sender` cannot be the zero address.
               * - `recipient` cannot be the zero address.
               * - `sender` must have a balance of at least `amount`.
               */
              function _transfer(address sender, address recipient, uint256 amount) internal {
                  require(sender != address(0), "ERC20: transfer from the zero address");
                  require(recipient != address(0), "ERC20: transfer to the zero address");
          
                  _balances[sender] = _balances[sender].sub(amount, "ERC20: transfer amount exceeds balance");
                  _balances[recipient] = _balances[recipient].add(amount);
                  emit Transfer(sender, recipient, amount);
              }
          
              /** @dev Creates `amount` tokens and assigns them to `account`, increasing
               * the total supply.
               *
               * Emits a {Transfer} event with `from` set to the zero address.
               *
               * Requirements
               *
               * - `to` cannot be the zero address.
               */
              function _mint(address account, uint256 amount) internal {
                  require(account != address(0), "ERC20: mint to the zero address");
          
                  _totalSupply = _totalSupply.add(amount);
                  _balances[account] = _balances[account].add(amount);
                  emit Transfer(address(0), account, amount);
              }
          
              /**
               * @dev Destroys `amount` tokens from `account`, reducing the
               * total supply.
               *
               * Emits a {Transfer} event with `to` set to the zero address.
               *
               * Requirements
               *
               * - `account` cannot be the zero address.
               * - `account` must have at least `amount` tokens.
               */
              function _burn(address account, uint256 amount) internal {
                  require(account != address(0), "ERC20: burn from the zero address");
          
                  _balances[account] = _balances[account].sub(amount, "ERC20: burn amount exceeds balance");
                  _totalSupply = _totalSupply.sub(amount);
                  emit Transfer(account, address(0), amount);
              }
          
              /**
               * @dev Sets `amount` as the allowance of `spender` over the `owner`s tokens.
               *
               * This is internal function is equivalent to `approve`, and can be used to
               * e.g. set automatic allowances for certain subsystems, etc.
               *
               * Emits an {Approval} event.
               *
               * Requirements:
               *
               * - `owner` cannot be the zero address.
               * - `spender` cannot be the zero address.
               */
              function _approve(address owner, address spender, uint256 amount) internal {
                  require(owner != address(0), "ERC20: approve from the zero address");
                  require(spender != address(0), "ERC20: approve to the zero address");
          
                  _allowances[owner][spender] = amount;
                  emit Approval(owner, spender, amount);
              }
          
              /**
               * @dev Destroys `amount` tokens from `account`.`amount` is then deducted
               * from the caller's allowance.
               *
               * See {_burn} and {_approve}.
               */
              function _burnFrom(address account, uint256 amount) internal {
                  _burn(account, amount);
                  _approve(account, _msgSender(), _allowances[account][_msgSender()].sub(amount, "ERC20: burn amount exceeds allowance"));
              }
          }
          
          // File: openzeppelin-solidity/contracts/access/Roles.sol
          
          pragma solidity ^0.5.0;
          
          /**
           * @title Roles
           * @dev Library for managing addresses assigned to a Role.
           */
          library Roles {
              struct Role {
                  mapping (address => bool) bearer;
              }
          
              /**
               * @dev Give an account access to this role.
               */
              function add(Role storage role, address account) internal {
                  require(!has(role, account), "Roles: account already has role");
                  role.bearer[account] = true;
              }
          
              /**
               * @dev Remove an account's access to this role.
               */
              function remove(Role storage role, address account) internal {
                  require(has(role, account), "Roles: account does not have role");
                  role.bearer[account] = false;
              }
          
              /**
               * @dev Check if an account has this role.
               * @return bool
               */
              function has(Role storage role, address account) internal view returns (bool) {
                  require(account != address(0), "Roles: account is the zero address");
                  return role.bearer[account];
              }
          }
          
          // File: openzeppelin-solidity/contracts/access/roles/MinterRole.sol
          
          pragma solidity ^0.5.0;
          
          
          
          contract MinterRole is Context {
              using Roles for Roles.Role;
          
              event MinterAdded(address indexed account);
              event MinterRemoved(address indexed account);
          
              Roles.Role private _minters;
          
              constructor () internal {
                  _addMinter(_msgSender());
              }
          
              modifier onlyMinter() {
                  require(isMinter(_msgSender()), "MinterRole: caller does not have the Minter role");
                  _;
              }
          
              function isMinter(address account) public view returns (bool) {
                  return _minters.has(account);
              }
          
              function addMinter(address account) public onlyMinter {
                  _addMinter(account);
              }
          
              function renounceMinter() public {
                  _removeMinter(_msgSender());
              }
          
              function _addMinter(address account) internal {
                  _minters.add(account);
                  emit MinterAdded(account);
              }
          
              function _removeMinter(address account) internal {
                  _minters.remove(account);
                  emit MinterRemoved(account);
              }
          }
          
          // File: openzeppelin-solidity/contracts/token/ERC20/ERC20Mintable.sol
          
          pragma solidity ^0.5.0;
          
          
          
          /**
           * @dev Extension of {ERC20} that adds a set of accounts with the {MinterRole},
           * which have permission to mint (create) new tokens as they see fit.
           *
           * At construction, the deployer of the contract is the only minter.
           */
          contract ERC20Mintable is ERC20, MinterRole {
              /**
               * @dev See {ERC20-_mint}.
               *
               * Requirements:
               *
               * - the caller must have the {MinterRole}.
               */
              function mint(address account, uint256 amount) public onlyMinter returns (bool) {
                  _mint(account, amount);
                  return true;
              }
          }
          
          // File: openzeppelin-solidity/contracts/token/ERC20/ERC20Detailed.sol
          
          pragma solidity ^0.5.0;
          
          
          /**
           * @dev Optional functions from the ERC20 standard.
           */
          contract ERC20Detailed is IERC20 {
              string private _name;
              string private _symbol;
              uint8 private _decimals;
          
              /**
               * @dev Sets the values for `name`, `symbol`, and `decimals`. All three of
               * these values are immutable: they can only be set once during
               * construction.
               */
              constructor (string memory name, string memory symbol, uint8 decimals) public {
                  _name = name;
                  _symbol = symbol;
                  _decimals = decimals;
              }
          
              /**
               * @dev Returns the name of the token.
               */
              function name() public view returns (string memory) {
                  return _name;
              }
          
              /**
               * @dev Returns the symbol of the token, usually a shorter version of the
               * name.
               */
              function symbol() public view returns (string memory) {
                  return _symbol;
              }
          
              /**
               * @dev Returns the number of decimals used to get its user representation.
               * For example, if `decimals` equals `2`, a balance of `505` tokens should
               * be displayed to a user as `5,05` (`505 / 10 ** 2`).
               *
               * Tokens usually opt for a value of 18, imitating the relationship between
               * Ether and Wei.
               *
               * NOTE: This information is only used for _display_ purposes: it in
               * no way affects any of the arithmetic of the contract, including
               * {IERC20-balanceOf} and {IERC20-transfer}.
               */
              function decimals() public view returns (uint8) {
                  return _decimals;
              }
          }
          
          // File: openzeppelin-solidity/contracts/introspection/ERC165Checker.sol
          
          pragma solidity ^0.5.10;
          
          /**
           * @dev Library used to query support of an interface declared via {IERC165}.
           *
           * Note that these functions return the actual result of the query: they do not
           * `revert` if an interface is not supported. It is up to the caller to decide
           * what to do in these cases.
           */
          library ERC165Checker {
              // As per the EIP-165 spec, no interface should ever match 0xffffffff
              bytes4 private constant _INTERFACE_ID_INVALID = 0xffffffff;
          
              /*
               * bytes4(keccak256('supportsInterface(bytes4)')) == 0x01ffc9a7
               */
              bytes4 private constant _INTERFACE_ID_ERC165 = 0x01ffc9a7;
          
              /**
               * @dev Returns true if `account` supports the {IERC165} interface,
               */
              function _supportsERC165(address account) internal view returns (bool) {
                  // Any contract that implements ERC165 must explicitly indicate support of
                  // InterfaceId_ERC165 and explicitly indicate non-support of InterfaceId_Invalid
                  return _supportsERC165Interface(account, _INTERFACE_ID_ERC165) &&
                      !_supportsERC165Interface(account, _INTERFACE_ID_INVALID);
              }
          
              /**
               * @dev Returns true if `account` supports the interface defined by
               * `interfaceId`. Support for {IERC165} itself is queried automatically.
               *
               * See {IERC165-supportsInterface}.
               */
              function _supportsInterface(address account, bytes4 interfaceId) internal view returns (bool) {
                  // query support of both ERC165 as per the spec and support of _interfaceId
                  return _supportsERC165(account) &&
                      _supportsERC165Interface(account, interfaceId);
              }
          
              /**
               * @dev Returns true if `account` supports all the interfaces defined in
               * `interfaceIds`. Support for {IERC165} itself is queried automatically.
               *
               * Batch-querying can lead to gas savings by skipping repeated checks for
               * {IERC165} support.
               *
               * See {IERC165-supportsInterface}.
               */
              function _supportsAllInterfaces(address account, bytes4[] memory interfaceIds) internal view returns (bool) {
                  // query support of ERC165 itself
                  if (!_supportsERC165(account)) {
                      return false;
                  }
          
                  // query support of each interface in _interfaceIds
                  for (uint256 i = 0; i < interfaceIds.length; i++) {
                      if (!_supportsERC165Interface(account, interfaceIds[i])) {
                          return false;
                      }
                  }
          
                  // all interfaces supported
                  return true;
              }
          
              /**
               * @notice Query if a contract implements an interface, does not check ERC165 support
               * @param account The address of the contract to query for support of an interface
               * @param interfaceId The interface identifier, as specified in ERC-165
               * @return true if the contract at account indicates support of the interface with
               * identifier interfaceId, false otherwise
               * @dev Assumes that account contains a contract that supports ERC165, otherwise
               * the behavior of this method is undefined. This precondition can be checked
               * with the `supportsERC165` method in this library.
               * Interface identification is specified in ERC-165.
               */
              function _supportsERC165Interface(address account, bytes4 interfaceId) private view returns (bool) {
                  // success determines whether the staticcall succeeded and result determines
                  // whether the contract at account indicates support of _interfaceId
                  (bool success, bool result) = _callERC165SupportsInterface(account, interfaceId);
          
                  return (success && result);
              }
          
              /**
               * @notice Calls the function with selector 0x01ffc9a7 (ERC165) and suppresses throw
               * @param account The address of the contract to query for support of an interface
               * @param interfaceId The interface identifier, as specified in ERC-165
               * @return success true if the STATICCALL succeeded, false otherwise
               * @return result true if the STATICCALL succeeded and the contract at account
               * indicates support of the interface with identifier interfaceId, false otherwise
               */
              function _callERC165SupportsInterface(address account, bytes4 interfaceId)
                  private
                  view
                  returns (bool, bool)
              {
                  bytes memory encodedParams = abi.encodeWithSelector(_INTERFACE_ID_ERC165, interfaceId);
                  (bool success, bytes memory result) = account.staticcall.gas(30000)(encodedParams);
                  if (result.length < 32) return (false, false);
                  return (success, abi.decode(result, (bool)));
              }
          }
          
          // File: contracts/stake/interfaces/SeigManagerI.sol
          
          pragma solidity ^0.5.12;
          
          
          interface SeigManagerI {
            function registry() external view returns (address);
            function depositManager() external view returns (address);
            function ton() external view returns (address);
            function wton() external view returns (address);
            function powerton() external view returns (address);
            function tot() external view returns (address);
            function coinages(address rootchain) external view returns (address);
            function commissionRates(address rootchain) external view returns (uint256);
          
            function lastCommitBlock(address rootchain) external view returns (uint256);
            function seigPerBlock() external view returns (uint256);
            function lastSeigBlock() external view returns (uint256);
            function pausedBlock() external view returns (uint256);
            function unpausedBlock() external view returns (uint256);
            function DEFAULT_FACTOR() external view returns (uint256);
          
            function deployCoinage(address rootchain) external returns (bool);
            function setCommissionRate(address rootchain, uint256 commission, bool isCommissionRateNegative) external returns (bool);
          
            function uncomittedStakeOf(address rootchain, address account) external view returns (uint256);
            function stakeOf(address rootchain, address account) external view returns (uint256);
            function additionalTotBurnAmount(address rootchain, address account, uint256 amount) external view returns (uint256 totAmount);
          
            function onTransfer(address sender, address recipient, uint256 amount) external returns (bool);
            function onCommit() external returns (bool);
            function onDeposit(address rootchain, address account, uint256 amount) external returns (bool);
            function onWithdraw(address rootchain, address account, uint256 amount) external returns (bool);
          
          }
          
          // File: openzeppelin-solidity/contracts/introspection/IERC165.sol
          
          pragma solidity ^0.5.0;
          
          /**
           * @dev Interface of the ERC165 standard, as defined in the
           * https://eips.ethereum.org/EIPS/eip-165[EIP].
           *
           * Implementers can declare support of contract interfaces, which can then be
           * queried by others ({ERC165Checker}).
           *
           * For an implementation, see {ERC165}.
           */
          interface IERC165 {
              /**
               * @dev Returns true if this contract implements the interface defined by
               * `interfaceId`. See the corresponding
               * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
               * to learn more about how these ids are created.
               *
               * This function call must use less than 30 000 gas.
               */
              function supportsInterface(bytes4 interfaceId) external view returns (bool);
          }
          
          // File: openzeppelin-solidity/contracts/introspection/ERC165.sol
          
          pragma solidity ^0.5.0;
          
          
          /**
           * @dev Implementation of the {IERC165} interface.
           *
           * Contracts may inherit from this and call {_registerInterface} to declare
           * their support of an interface.
           */
          contract ERC165 is IERC165 {
              /*
               * bytes4(keccak256('supportsInterface(bytes4)')) == 0x01ffc9a7
               */
              bytes4 private constant _INTERFACE_ID_ERC165 = 0x01ffc9a7;
          
              /**
               * @dev Mapping of interface ids to whether or not it's supported.
               */
              mapping(bytes4 => bool) private _supportedInterfaces;
          
              constructor () internal {
                  // Derived contracts need only register support for their own interfaces,
                  // we register support for ERC165 itself here
                  _registerInterface(_INTERFACE_ID_ERC165);
              }
          
              /**
               * @dev See {IERC165-supportsInterface}.
               *
               * Time complexity O(1), guaranteed to always use less than 30 000 gas.
               */
              function supportsInterface(bytes4 interfaceId) external view returns (bool) {
                  return _supportedInterfaces[interfaceId];
              }
          
              /**
               * @dev Registers the contract as an implementer of the interface defined by
               * `interfaceId`. Support of the actual ERC165 interface is automatic and
               * registering its interface id is not required.
               *
               * See {IERC165-supportsInterface}.
               *
               * Requirements:
               *
               * - `interfaceId` cannot be the ERC165 invalid interface (`0xffffffff`).
               */
              function _registerInterface(bytes4 interfaceId) internal {
                  require(interfaceId != 0xffffffff, "ERC165: invalid interface id");
                  _supportedInterfaces[interfaceId] = true;
              }
          }
          
          // File: contracts/stake/tokens/OnApprove.sol
          
          pragma solidity ^0.5.12;
          
          
          contract OnApprove is ERC165 {
            constructor() public {
              _registerInterface(OnApprove(this).onApprove.selector);
            }
          
            function onApprove(address owner, address spender, uint256 amount, bytes calldata data) external returns (bool);
          }
          
          // File: contracts/stake/tokens/ERC20OnApprove.sol
          
          pragma solidity ^0.5.12;
          
          
          
          
          
          contract ERC20OnApprove is ERC20 {
            function approveAndCall(address spender, uint256 amount, bytes memory data) public returns (bool) {
              require(approve(spender, amount));
              _callOnApprove(msg.sender, spender, amount, data);
              return true;
            }
          
            function _callOnApprove(address owner, address spender, uint256 amount, bytes memory data) internal {
              bytes4 onApproveSelector = OnApprove(spender).onApprove.selector;
          
              require(ERC165Checker._supportsInterface(spender, onApproveSelector),
                "ERC20OnApprove: spender doesn't support onApprove");
          
              (bool ok, bytes memory res) = spender.call(
                abi.encodeWithSelector(
                  onApproveSelector,
                  owner,
                  spender,
                  amount,
                  data
                )
              );
          
              // check if low-level call reverted or not
              require(ok, string(res));
          
              assembly {
                ok := mload(add(res, 0x20))
              }
          
              // check if OnApprove.onApprove returns true or false
              require(ok, "ERC20OnApprove: failed to call onApprove");
            }
          
          }
          
          // File: contracts/stake/tokens/AuthController.sol
          
          pragma solidity ^0.5.12;
          
          
          
          interface MinterRoleRenounceTarget {
            function renounceMinter() external;
          }
          
          interface PauserRoleRenounceTarget {
            function renouncePauser() external;
          }
          
          interface OwnableTarget {
            function renounceOwnership() external;
            function transferOwnership(address newOwner) external;
          }
          
          contract AuthController is Ownable {
            function renounceMinter(address target) public onlyOwner {
              MinterRoleRenounceTarget(target).renounceMinter();
            }
          
            function renouncePauser(address target) public onlyOwner {
              PauserRoleRenounceTarget(target).renouncePauser();
            }
          
            function renounceOwnership(address target) public onlyOwner {
              OwnableTarget(target).renounceOwnership();
            }
          
            function transferOwnership(address target, address newOwner) public onlyOwner {
              OwnableTarget(target).transferOwnership(newOwner);
            }
          }
          
          // File: contracts/stake/tokens/SeigToken.sol
          
          pragma solidity ^0.5.12;
          
          
          
          
          
          
          
          contract SeigToken is ERC20, Ownable, ERC20OnApprove, AuthController {
            SeigManagerI public seigManager;
            bool public callbackEnabled;
          
            function enableCallback(bool _callbackEnabled) external onlyOwner {
              callbackEnabled = _callbackEnabled;
            }
          
            function setSeigManager(SeigManagerI _seigManager) external onlyOwner {
              seigManager = _seigManager;
            }
          
            //////////////////////
            // Override ERC20 functions
            //////////////////////
          
            function transferFrom(address sender, address recipient, uint256 amount) public returns (bool) {
              require(msg.sender == sender || msg.sender == recipient, "SeigToken: only sender or recipient can transfer");
              return super.transferFrom(sender, recipient, amount);
            }
          
            function _transfer(address sender, address recipient, uint256 amount) internal {
              super._transfer(sender, recipient, amount);
              if (callbackEnabled && address(seigManager) != address(0)) {
                require(seigManager.onTransfer(sender, recipient, amount));
              }
            }
          
            function _mint(address account, uint256 amount) internal {
              super._mint(account, amount);
              if (callbackEnabled && address(seigManager) != address(0)) {
                require(seigManager.onTransfer(address(0), account, amount));
              }
            }
          
            function _burn(address account, uint256 amount) internal {
              super._burn(account, amount);
              if (callbackEnabled && address(seigManager) != address(0)) {
                require(seigManager.onTransfer(account, address(0), amount));
              }
            }
          }
          
          // File: contracts/stake/tokens/TON.sol
          
          pragma solidity ^0.5.12;
          
          
          
          
          
          
          
          
          /**
           * @dev Current implementations is just for testing seigniorage manager.
           */
          contract TON is Ownable, ERC20Mintable, ERC20Detailed, SeigToken {
            constructor() public ERC20Detailed("Tokamak Network Token", "TON", 18) {}
          
            function setSeigManager(SeigManagerI _seigManager) external {
              revert("TON: TON doesn't allow setSeigManager");
            }
          }

          File 2 of 8: WTON
          // File: openzeppelin-solidity/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-solidity/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 {
                  address msgSender = _msgSender();
                  _owner = msgSender;
                  emit OwnershipTransferred(address(0), msgSender);
              }
          
              /**
               * @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-solidity/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-solidity/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);
          
              /**
               * @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-solidity/contracts/token/ERC20/ERC20.sol
          
          pragma solidity ^0.5.0;
          
          
          
          
          /**
           * @dev Implementation of the {IERC20} interface.
           *
           * This implementation is agnostic to the way tokens are created. This means
           * that a supply mechanism has to be added in a derived contract using {_mint}.
           * For a generic mechanism see {ERC20Mintable}.
           *
           * TIP: For a detailed writeup see our guide
           * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How
           * to implement supply mechanisms].
           *
           * We have followed general OpenZeppelin guidelines: functions revert instead
           * of returning `false` on failure. This behavior is nonetheless conventional
           * and does not conflict with the expectations of ERC20 applications.
           *
           * Additionally, an {Approval} event is emitted on calls to {transferFrom}.
           * This allows applications to reconstruct the allowance for all accounts just
           * by listening to said events. Other implementations of the EIP may not emit
           * these events, as it isn't required by the specification.
           *
           * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}
           * functions have been added to mitigate the well-known issues around setting
           * allowances. See {IERC20-approve}.
           */
          contract ERC20 is Context, IERC20 {
              using SafeMath for uint256;
          
              mapping (address => uint256) private _balances;
          
              mapping (address => mapping (address => uint256)) private _allowances;
          
              uint256 private _totalSupply;
          
              /**
               * @dev See {IERC20-totalSupply}.
               */
              function totalSupply() public view returns (uint256) {
                  return _totalSupply;
              }
          
              /**
               * @dev See {IERC20-balanceOf}.
               */
              function balanceOf(address account) public view returns (uint256) {
                  return _balances[account];
              }
          
              /**
               * @dev See {IERC20-transfer}.
               *
               * Requirements:
               *
               * - `recipient` cannot be the zero address.
               * - the caller must have a balance of at least `amount`.
               */
              function transfer(address recipient, uint256 amount) public returns (bool) {
                  _transfer(_msgSender(), recipient, amount);
                  return true;
              }
          
              /**
               * @dev See {IERC20-allowance}.
               */
              function allowance(address owner, address spender) public view returns (uint256) {
                  return _allowances[owner][spender];
              }
          
              /**
               * @dev See {IERC20-approve}.
               *
               * Requirements:
               *
               * - `spender` cannot be the zero address.
               */
              function approve(address spender, uint256 amount) public returns (bool) {
                  _approve(_msgSender(), spender, amount);
                  return true;
              }
          
              /**
               * @dev See {IERC20-transferFrom}.
               *
               * Emits an {Approval} event indicating the updated allowance. This is not
               * required by the EIP. See the note at the beginning of {ERC20};
               *
               * Requirements:
               * - `sender` and `recipient` cannot be the zero address.
               * - `sender` must have a balance of at least `amount`.
               * - the caller must have allowance for `sender`'s tokens of at least
               * `amount`.
               */
              function transferFrom(address sender, address recipient, uint256 amount) public returns (bool) {
                  _transfer(sender, recipient, amount);
                  _approve(sender, _msgSender(), _allowances[sender][_msgSender()].sub(amount, "ERC20: transfer amount exceeds allowance"));
                  return true;
              }
          
              /**
               * @dev Atomically increases the allowance granted to `spender` by the caller.
               *
               * This is an alternative to {approve} that can be used as a mitigation for
               * problems described in {IERC20-approve}.
               *
               * Emits an {Approval} event indicating the updated allowance.
               *
               * Requirements:
               *
               * - `spender` cannot be the zero address.
               */
              function increaseAllowance(address spender, uint256 addedValue) public returns (bool) {
                  _approve(_msgSender(), spender, _allowances[_msgSender()][spender].add(addedValue));
                  return true;
              }
          
              /**
               * @dev Atomically decreases the allowance granted to `spender` by the caller.
               *
               * This is an alternative to {approve} that can be used as a mitigation for
               * problems described in {IERC20-approve}.
               *
               * Emits an {Approval} event indicating the updated allowance.
               *
               * Requirements:
               *
               * - `spender` cannot be the zero address.
               * - `spender` must have allowance for the caller of at least
               * `subtractedValue`.
               */
              function decreaseAllowance(address spender, uint256 subtractedValue) public returns (bool) {
                  _approve(_msgSender(), spender, _allowances[_msgSender()][spender].sub(subtractedValue, "ERC20: decreased allowance below zero"));
                  return true;
              }
          
              /**
               * @dev Moves tokens `amount` from `sender` to `recipient`.
               *
               * This is internal function is equivalent to {transfer}, and can be used to
               * e.g. implement automatic token fees, slashing mechanisms, etc.
               *
               * Emits a {Transfer} event.
               *
               * Requirements:
               *
               * - `sender` cannot be the zero address.
               * - `recipient` cannot be the zero address.
               * - `sender` must have a balance of at least `amount`.
               */
              function _transfer(address sender, address recipient, uint256 amount) internal {
                  require(sender != address(0), "ERC20: transfer from the zero address");
                  require(recipient != address(0), "ERC20: transfer to the zero address");
          
                  _balances[sender] = _balances[sender].sub(amount, "ERC20: transfer amount exceeds balance");
                  _balances[recipient] = _balances[recipient].add(amount);
                  emit Transfer(sender, recipient, amount);
              }
          
              /** @dev Creates `amount` tokens and assigns them to `account`, increasing
               * the total supply.
               *
               * Emits a {Transfer} event with `from` set to the zero address.
               *
               * Requirements
               *
               * - `to` cannot be the zero address.
               */
              function _mint(address account, uint256 amount) internal {
                  require(account != address(0), "ERC20: mint to the zero address");
          
                  _totalSupply = _totalSupply.add(amount);
                  _balances[account] = _balances[account].add(amount);
                  emit Transfer(address(0), account, amount);
              }
          
              /**
               * @dev Destroys `amount` tokens from `account`, reducing the
               * total supply.
               *
               * Emits a {Transfer} event with `to` set to the zero address.
               *
               * Requirements
               *
               * - `account` cannot be the zero address.
               * - `account` must have at least `amount` tokens.
               */
              function _burn(address account, uint256 amount) internal {
                  require(account != address(0), "ERC20: burn from the zero address");
          
                  _balances[account] = _balances[account].sub(amount, "ERC20: burn amount exceeds balance");
                  _totalSupply = _totalSupply.sub(amount);
                  emit Transfer(account, address(0), amount);
              }
          
              /**
               * @dev Sets `amount` as the allowance of `spender` over the `owner`s tokens.
               *
               * This is internal function is equivalent to `approve`, and can be used to
               * e.g. set automatic allowances for certain subsystems, etc.
               *
               * Emits an {Approval} event.
               *
               * Requirements:
               *
               * - `owner` cannot be the zero address.
               * - `spender` cannot be the zero address.
               */
              function _approve(address owner, address spender, uint256 amount) internal {
                  require(owner != address(0), "ERC20: approve from the zero address");
                  require(spender != address(0), "ERC20: approve to the zero address");
          
                  _allowances[owner][spender] = amount;
                  emit Approval(owner, spender, amount);
              }
          
              /**
               * @dev Destroys `amount` tokens from `account`.`amount` is then deducted
               * from the caller's allowance.
               *
               * See {_burn} and {_approve}.
               */
              function _burnFrom(address account, uint256 amount) internal {
                  _burn(account, amount);
                  _approve(account, _msgSender(), _allowances[account][_msgSender()].sub(amount, "ERC20: burn amount exceeds allowance"));
              }
          }
          
          // File: openzeppelin-solidity/contracts/access/Roles.sol
          
          pragma solidity ^0.5.0;
          
          /**
           * @title Roles
           * @dev Library for managing addresses assigned to a Role.
           */
          library Roles {
              struct Role {
                  mapping (address => bool) bearer;
              }
          
              /**
               * @dev Give an account access to this role.
               */
              function add(Role storage role, address account) internal {
                  require(!has(role, account), "Roles: account already has role");
                  role.bearer[account] = true;
              }
          
              /**
               * @dev Remove an account's access to this role.
               */
              function remove(Role storage role, address account) internal {
                  require(has(role, account), "Roles: account does not have role");
                  role.bearer[account] = false;
              }
          
              /**
               * @dev Check if an account has this role.
               * @return bool
               */
              function has(Role storage role, address account) internal view returns (bool) {
                  require(account != address(0), "Roles: account is the zero address");
                  return role.bearer[account];
              }
          }
          
          // File: openzeppelin-solidity/contracts/access/roles/MinterRole.sol
          
          pragma solidity ^0.5.0;
          
          
          
          contract MinterRole is Context {
              using Roles for Roles.Role;
          
              event MinterAdded(address indexed account);
              event MinterRemoved(address indexed account);
          
              Roles.Role private _minters;
          
              constructor () internal {
                  _addMinter(_msgSender());
              }
          
              modifier onlyMinter() {
                  require(isMinter(_msgSender()), "MinterRole: caller does not have the Minter role");
                  _;
              }
          
              function isMinter(address account) public view returns (bool) {
                  return _minters.has(account);
              }
          
              function addMinter(address account) public onlyMinter {
                  _addMinter(account);
              }
          
              function renounceMinter() public {
                  _removeMinter(_msgSender());
              }
          
              function _addMinter(address account) internal {
                  _minters.add(account);
                  emit MinterAdded(account);
              }
          
              function _removeMinter(address account) internal {
                  _minters.remove(account);
                  emit MinterRemoved(account);
              }
          }
          
          // File: openzeppelin-solidity/contracts/token/ERC20/ERC20Mintable.sol
          
          pragma solidity ^0.5.0;
          
          
          
          /**
           * @dev Extension of {ERC20} that adds a set of accounts with the {MinterRole},
           * which have permission to mint (create) new tokens as they see fit.
           *
           * At construction, the deployer of the contract is the only minter.
           */
          contract ERC20Mintable is ERC20, MinterRole {
              /**
               * @dev See {ERC20-_mint}.
               *
               * Requirements:
               *
               * - the caller must have the {MinterRole}.
               */
              function mint(address account, uint256 amount) public onlyMinter returns (bool) {
                  _mint(account, amount);
                  return true;
              }
          }
          
          // File: openzeppelin-solidity/contracts/token/ERC20/ERC20Burnable.sol
          
          pragma solidity ^0.5.0;
          
          
          
          /**
           * @dev Extension of {ERC20} that allows token holders to destroy both their own
           * tokens and those that they have an allowance for, in a way that can be
           * recognized off-chain (via event analysis).
           */
          contract ERC20Burnable is Context, ERC20 {
              /**
               * @dev Destroys `amount` tokens from the caller.
               *
               * See {ERC20-_burn}.
               */
              function burn(uint256 amount) public {
                  _burn(_msgSender(), amount);
              }
          
              /**
               * @dev See {ERC20-_burnFrom}.
               */
              function burnFrom(address account, uint256 amount) public {
                  _burnFrom(account, amount);
              }
          }
          
          // File: openzeppelin-solidity/contracts/token/ERC20/ERC20Detailed.sol
          
          pragma solidity ^0.5.0;
          
          
          /**
           * @dev Optional functions from the ERC20 standard.
           */
          contract ERC20Detailed is IERC20 {
              string private _name;
              string private _symbol;
              uint8 private _decimals;
          
              /**
               * @dev Sets the values for `name`, `symbol`, and `decimals`. All three of
               * these values are immutable: they can only be set once during
               * construction.
               */
              constructor (string memory name, string memory symbol, uint8 decimals) public {
                  _name = name;
                  _symbol = symbol;
                  _decimals = decimals;
              }
          
              /**
               * @dev Returns the name of the token.
               */
              function name() public view returns (string memory) {
                  return _name;
              }
          
              /**
               * @dev Returns the symbol of the token, usually a shorter version of the
               * name.
               */
              function symbol() public view returns (string memory) {
                  return _symbol;
              }
          
              /**
               * @dev Returns the number of decimals used to get its user representation.
               * For example, if `decimals` equals `2`, a balance of `505` tokens should
               * be displayed to a user as `5,05` (`505 / 10 ** 2`).
               *
               * Tokens usually opt for a value of 18, imitating the relationship between
               * Ether and Wei.
               *
               * NOTE: This information is only used for _display_ purposes: it in
               * no way affects any of the arithmetic of the contract, including
               * {IERC20-balanceOf} and {IERC20-transfer}.
               */
              function decimals() public view returns (uint8) {
                  return _decimals;
              }
          }
          
          // File: openzeppelin-solidity/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.
               *
               * [IMPORTANT]
               * ====
               * It is unsafe to assume that an address for which this function returns
               * false is an externally-owned account (EOA) and not a contract.
               *
               * Among others, `isContract` will return false for the following 
               * types of addresses:
               *
               *  - an externally-owned account
               *  - a contract in construction
               *  - an address where a contract will be created
               *  - an address where a contract lived, but was destroyed
               * ====
               */
              function isContract(address account) internal view returns (bool) {
                  // 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 != accountHash && codehash != 0x0);
              }
          
              /**
               * @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-solidity/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: openzeppelin-solidity/contracts/utils/ReentrancyGuard.sol
          
          pragma solidity ^0.5.0;
          
          /**
           * @dev Contract module that helps prevent reentrant calls to a function.
           *
           * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
           * available, which can be applied to functions to make sure there are no nested
           * (reentrant) calls to them.
           *
           * Note that because there is a single `nonReentrant` guard, functions marked as
           * `nonReentrant` may not call one another. This can be worked around by making
           * those functions `private`, and then adding `external` `nonReentrant` entry
           * points to them.
           *
           * TIP: If you would like to learn more about reentrancy and alternative ways
           * to protect against it, check out our blog post
           * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
           *
           * _Since v2.5.0:_ this module is now much more gas efficient, given net gas
           * metering changes introduced in the Istanbul hardfork.
           */
          contract ReentrancyGuard {
              bool private _notEntered;
          
              constructor () internal {
                  // Storing an initial non-zero value makes deployment a bit more
                  // expensive, but in exchange the refund on every call to nonReentrant
                  // will be lower in amount. Since refunds are capped to a percetange of
                  // the total transaction's gas, it is best to keep them low in cases
                  // like this one, to increase the likelihood of the full refund coming
                  // into effect.
                  _notEntered = true;
              }
          
              /**
               * @dev Prevents a contract from calling itself, directly or indirectly.
               * Calling a `nonReentrant` function from another `nonReentrant`
               * function is not supported. It is possible to prevent this from happening
               * by making the `nonReentrant` function external, and make it call a
               * `private` function that does the actual work.
               */
              modifier nonReentrant() {
                  // On the first call to nonReentrant, _notEntered will be true
                  require(_notEntered, "ReentrancyGuard: reentrant call");
          
                  // Any calls to nonReentrant after this point will fail
                  _notEntered = false;
          
                  _;
          
                  // By storing the original value once again, a refund is triggered (see
                  // https://eips.ethereum.org/EIPS/eip-2200)
                  _notEntered = true;
              }
          }
          
          // File: openzeppelin-solidity/contracts/introspection/IERC165.sol
          
          pragma solidity ^0.5.0;
          
          /**
           * @dev Interface of the ERC165 standard, as defined in the
           * https://eips.ethereum.org/EIPS/eip-165[EIP].
           *
           * Implementers can declare support of contract interfaces, which can then be
           * queried by others ({ERC165Checker}).
           *
           * For an implementation, see {ERC165}.
           */
          interface IERC165 {
              /**
               * @dev Returns true if this contract implements the interface defined by
               * `interfaceId`. See the corresponding
               * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
               * to learn more about how these ids are created.
               *
               * This function call must use less than 30 000 gas.
               */
              function supportsInterface(bytes4 interfaceId) external view returns (bool);
          }
          
          // File: openzeppelin-solidity/contracts/introspection/ERC165.sol
          
          pragma solidity ^0.5.0;
          
          
          /**
           * @dev Implementation of the {IERC165} interface.
           *
           * Contracts may inherit from this and call {_registerInterface} to declare
           * their support of an interface.
           */
          contract ERC165 is IERC165 {
              /*
               * bytes4(keccak256('supportsInterface(bytes4)')) == 0x01ffc9a7
               */
              bytes4 private constant _INTERFACE_ID_ERC165 = 0x01ffc9a7;
          
              /**
               * @dev Mapping of interface ids to whether or not it's supported.
               */
              mapping(bytes4 => bool) private _supportedInterfaces;
          
              constructor () internal {
                  // Derived contracts need only register support for their own interfaces,
                  // we register support for ERC165 itself here
                  _registerInterface(_INTERFACE_ID_ERC165);
              }
          
              /**
               * @dev See {IERC165-supportsInterface}.
               *
               * Time complexity O(1), guaranteed to always use less than 30 000 gas.
               */
              function supportsInterface(bytes4 interfaceId) external view returns (bool) {
                  return _supportedInterfaces[interfaceId];
              }
          
              /**
               * @dev Registers the contract as an implementer of the interface defined by
               * `interfaceId`. Support of the actual ERC165 interface is automatic and
               * registering its interface id is not required.
               *
               * See {IERC165-supportsInterface}.
               *
               * Requirements:
               *
               * - `interfaceId` cannot be the ERC165 invalid interface (`0xffffffff`).
               */
              function _registerInterface(bytes4 interfaceId) internal {
                  require(interfaceId != 0xffffffff, "ERC165: invalid interface id");
                  _supportedInterfaces[interfaceId] = true;
              }
          }
          
          // File: openzeppelin-solidity/contracts/introspection/ERC165Checker.sol
          
          pragma solidity ^0.5.10;
          
          /**
           * @dev Library used to query support of an interface declared via {IERC165}.
           *
           * Note that these functions return the actual result of the query: they do not
           * `revert` if an interface is not supported. It is up to the caller to decide
           * what to do in these cases.
           */
          library ERC165Checker {
              // As per the EIP-165 spec, no interface should ever match 0xffffffff
              bytes4 private constant _INTERFACE_ID_INVALID = 0xffffffff;
          
              /*
               * bytes4(keccak256('supportsInterface(bytes4)')) == 0x01ffc9a7
               */
              bytes4 private constant _INTERFACE_ID_ERC165 = 0x01ffc9a7;
          
              /**
               * @dev Returns true if `account` supports the {IERC165} interface,
               */
              function _supportsERC165(address account) internal view returns (bool) {
                  // Any contract that implements ERC165 must explicitly indicate support of
                  // InterfaceId_ERC165 and explicitly indicate non-support of InterfaceId_Invalid
                  return _supportsERC165Interface(account, _INTERFACE_ID_ERC165) &&
                      !_supportsERC165Interface(account, _INTERFACE_ID_INVALID);
              }
          
              /**
               * @dev Returns true if `account` supports the interface defined by
               * `interfaceId`. Support for {IERC165} itself is queried automatically.
               *
               * See {IERC165-supportsInterface}.
               */
              function _supportsInterface(address account, bytes4 interfaceId) internal view returns (bool) {
                  // query support of both ERC165 as per the spec and support of _interfaceId
                  return _supportsERC165(account) &&
                      _supportsERC165Interface(account, interfaceId);
              }
          
              /**
               * @dev Returns true if `account` supports all the interfaces defined in
               * `interfaceIds`. Support for {IERC165} itself is queried automatically.
               *
               * Batch-querying can lead to gas savings by skipping repeated checks for
               * {IERC165} support.
               *
               * See {IERC165-supportsInterface}.
               */
              function _supportsAllInterfaces(address account, bytes4[] memory interfaceIds) internal view returns (bool) {
                  // query support of ERC165 itself
                  if (!_supportsERC165(account)) {
                      return false;
                  }
          
                  // query support of each interface in _interfaceIds
                  for (uint256 i = 0; i < interfaceIds.length; i++) {
                      if (!_supportsERC165Interface(account, interfaceIds[i])) {
                          return false;
                      }
                  }
          
                  // all interfaces supported
                  return true;
              }
          
              /**
               * @notice Query if a contract implements an interface, does not check ERC165 support
               * @param account The address of the contract to query for support of an interface
               * @param interfaceId The interface identifier, as specified in ERC-165
               * @return true if the contract at account indicates support of the interface with
               * identifier interfaceId, false otherwise
               * @dev Assumes that account contains a contract that supports ERC165, otherwise
               * the behavior of this method is undefined. This precondition can be checked
               * with the `supportsERC165` method in this library.
               * Interface identification is specified in ERC-165.
               */
              function _supportsERC165Interface(address account, bytes4 interfaceId) private view returns (bool) {
                  // success determines whether the staticcall succeeded and result determines
                  // whether the contract at account indicates support of _interfaceId
                  (bool success, bool result) = _callERC165SupportsInterface(account, interfaceId);
          
                  return (success && result);
              }
          
              /**
               * @notice Calls the function with selector 0x01ffc9a7 (ERC165) and suppresses throw
               * @param account The address of the contract to query for support of an interface
               * @param interfaceId The interface identifier, as specified in ERC-165
               * @return success true if the STATICCALL succeeded, false otherwise
               * @return result true if the STATICCALL succeeded and the contract at account
               * indicates support of the interface with identifier interfaceId, false otherwise
               */
              function _callERC165SupportsInterface(address account, bytes4 interfaceId)
                  private
                  view
                  returns (bool, bool)
              {
                  bytes memory encodedParams = abi.encodeWithSelector(_INTERFACE_ID_ERC165, interfaceId);
                  (bool success, bytes memory result) = account.staticcall.gas(30000)(encodedParams);
                  if (result.length < 32) return (false, false);
                  return (success, abi.decode(result, (bool)));
              }
          }
          
          // File: coinage-token/contracts/lib/DSMath.sol
          
          // https://github.com/dapphub/ds-math/blob/de45767/src/math.sol
          /// math.sol -- mixin for inline numerical wizardry
          
          // This program is free software: you can redistribute it and/or modify
          // it under the terms of the GNU General Public License as published by
          // the Free Software Foundation, either version 3 of the License, or
          // (at your option) any later version.
          
          // This program is distributed in the hope that it will be useful,
          // but WITHOUT ANY WARRANTY; without even the implied warranty of
          // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
          // GNU General Public License for more details.
          
          // You should have received a copy of the GNU General Public License
          // along with this program.  If not, see <http://www.gnu.org/licenses/>.
          
          pragma solidity >0.4.13;
          
          contract DSMath {
            function add(uint x, uint y) internal pure returns (uint z) {
              require((z = x + y) >= x, "ds-math-add-overflow");
            }
            function sub(uint x, uint y) internal pure returns (uint z) {
              require((z = x - y) <= x, "ds-math-sub-underflow");
            }
            function mul(uint x, uint y) internal pure returns (uint z) {
              require(y == 0 || (z = x * y) / y == x, "ds-math-mul-overflow");
            }
          
            function min(uint x, uint y) internal pure returns (uint z) {
              return x <= y ? x : y;
            }
            function max(uint x, uint y) internal pure returns (uint z) {
              return x >= y ? x : y;
            }
            function imin(int x, int y) internal pure returns (int z) {
              return x <= y ? x : y;
            }
            function imax(int x, int y) internal pure returns (int z) {
              return x >= y ? x : y;
            }
          
            uint constant WAD = 10 ** 18;
            uint constant RAY = 10 ** 27;
          
            function wmul(uint x, uint y) internal pure returns (uint z) {
              z = add(mul(x, y), WAD / 2) / WAD;
            }
            function rmul(uint x, uint y) internal pure returns (uint z) {
              z = add(mul(x, y), RAY / 2) / RAY;
            }
            function wdiv(uint x, uint y) internal pure returns (uint z) {
              z = add(mul(x, WAD), y / 2) / y;
            }
            function rdiv(uint x, uint y) internal pure returns (uint z) {
              z = add(mul(x, RAY), y / 2) / y;
            }
          
            // This famous algorithm is called "exponentiation by squaring"
            // and calculates x^n with x as fixed-point and n as regular unsigned.
            //
            // It's O(log n), instead of O(n) for naive repeated multiplication.
            //
            // These facts are why it works:
            //
            //  If n is even, then x^n = (x^2)^(n/2).
            //  If n is odd,  then x^n = x * x^(n-1),
            //   and applying the equation for even x gives
            //  x^n = x * (x^2)^((n-1) / 2).
            //
            //  Also, EVM division is flooring and
            //  floor[(n-1) / 2] = floor[n / 2].
            //
            function wpow(uint x, uint n) internal pure returns (uint z) {
              z = n % 2 != 0 ? x : WAD;
          
              for (n /= 2; n != 0; n /= 2) {
                x = wmul(x, x);
          
                if (n % 2 != 0) {
                  z = wmul(z, x);
                }
              }
            }
          
            function rpow(uint x, uint n) internal pure returns (uint z) {
              z = n % 2 != 0 ? x : RAY;
          
              for (n /= 2; n != 0; n /= 2) {
                x = rmul(x, x);
          
                if (n % 2 != 0) {
                  z = rmul(z, x);
                }
              }
            }
          }
          
          // File: contracts/stake/interfaces/SeigManagerI.sol
          
          pragma solidity ^0.5.12;
          
          
          interface SeigManagerI {
            function registry() external view returns (address);
            function depositManager() external view returns (address);
            function ton() external view returns (address);
            function wton() external view returns (address);
            function powerton() external view returns (address);
            function tot() external view returns (address);
            function coinages(address layer2) external view returns (address);
            function commissionRates(address layer2) external view returns (uint256);
          
            function lastCommitBlock(address layer2) external view returns (uint256);
            function seigPerBlock() external view returns (uint256);
            function lastSeigBlock() external view returns (uint256);
            function pausedBlock() external view returns (uint256);
            function unpausedBlock() external view returns (uint256);
            function DEFAULT_FACTOR() external view returns (uint256);
          
            function deployCoinage(address layer2) external returns (bool);
            function setCommissionRate(address layer2, uint256 commission, bool isCommissionRateNegative) external returns (bool);
          
            function uncomittedStakeOf(address layer2, address account) external view returns (uint256);
            function stakeOf(address layer2, address account) external view returns (uint256);
            function additionalTotBurnAmount(address layer2, address account, uint256 amount) external view returns (uint256 totAmount);
          
            function onTransfer(address sender, address recipient, uint256 amount) external returns (bool);
            function updateSeigniorage() external returns (bool);
            function onDeposit(address layer2, address account, uint256 amount) external returns (bool);
            function onWithdraw(address layer2, address account, uint256 amount) external returns (bool);
          
          }
          
          // File: contracts/stake/tokens/OnApprove.sol
          
          pragma solidity ^0.5.12;
          
          
          contract OnApprove is ERC165 {
            constructor() public {
              _registerInterface(OnApprove(this).onApprove.selector);
            }
          
            function onApprove(address owner, address spender, uint256 amount, bytes calldata data) external returns (bool);
          }
          
          // File: contracts/stake/tokens/ERC20OnApprove.sol
          
          pragma solidity ^0.5.12;
          
          
          
          
          
          contract ERC20OnApprove is ERC20 {
            function approveAndCall(address spender, uint256 amount, bytes memory data) public returns (bool) {
              require(approve(spender, amount));
              _callOnApprove(msg.sender, spender, amount, data);
              return true;
            }
          
            function _callOnApprove(address owner, address spender, uint256 amount, bytes memory data) internal {
              bytes4 onApproveSelector = OnApprove(spender).onApprove.selector;
          
              require(ERC165Checker._supportsInterface(spender, onApproveSelector),
                "ERC20OnApprove: spender doesn't support onApprove");
          
              (bool ok, bytes memory res) = spender.call(
                abi.encodeWithSelector(
                  onApproveSelector,
                  owner,
                  spender,
                  amount,
                  data
                )
              );
          
              // check if low-level call reverted or not
              require(ok, string(res));
          
              assembly {
                ok := mload(add(res, 0x20))
              }
          
              // check if OnApprove.onApprove returns true or false
              require(ok, "ERC20OnApprove: failed to call onApprove");
            }
          
          }
          
          // File: contracts/stake/tokens/AuthController.sol
          
          pragma solidity ^0.5.12;
          
          
          
          interface MinterRoleRenounceTarget {
            function renounceMinter() external;
          }
          
          interface PauserRoleRenounceTarget {
            function renouncePauser() external;
          }
          
          interface OwnableTarget {
            function renounceOwnership() external;
            function transferOwnership(address newOwner) external;
          }
          
          contract AuthController is Ownable {
            function renounceMinter(address target) public onlyOwner {
              MinterRoleRenounceTarget(target).renounceMinter();
            }
          
            function renouncePauser(address target) public onlyOwner {
              PauserRoleRenounceTarget(target).renouncePauser();
            }
          
            function renounceOwnership(address target) public onlyOwner {
              OwnableTarget(target).renounceOwnership();
            }
          
            function transferOwnership(address target, address newOwner) public onlyOwner {
              OwnableTarget(target).transferOwnership(newOwner);
            }
          }
          
          // File: contracts/stake/tokens/SeigToken.sol
          
          pragma solidity ^0.5.12;
          
          
          
          
          
          
          
          contract SeigToken is ERC20, Ownable, ERC20OnApprove, AuthController {
            SeigManagerI public seigManager;
            bool public callbackEnabled;
          
            function enableCallback(bool _callbackEnabled) external onlyOwner {
              callbackEnabled = _callbackEnabled;
            }
          
            function setSeigManager(SeigManagerI _seigManager) external onlyOwner {
              seigManager = _seigManager;
            }
          
            //////////////////////
            // Override ERC20 functions
            //////////////////////
          
            function transferFrom(address sender, address recipient, uint256 amount) public returns (bool) {
              return super.transferFrom(sender, recipient, amount);
            }
          
            function _transfer(address sender, address recipient, uint256 amount) internal {
              super._transfer(sender, recipient, amount);
              if (callbackEnabled && address(seigManager) != address(0)) {
                require(seigManager.onTransfer(sender, recipient, amount));
              }
            }
          
            function _mint(address account, uint256 amount) internal {
              super._mint(account, amount);
              if (callbackEnabled && address(seigManager) != address(0)) {
                require(seigManager.onTransfer(address(0), account, amount));
              }
            }
          
            function _burn(address account, uint256 amount) internal {
              super._burn(account, amount);
              if (callbackEnabled && address(seigManager) != address(0)) {
                require(seigManager.onTransfer(account, address(0), amount));
              }
            }
          }
          
          // File: contracts/stake/tokens/WTON.sol
          
          pragma solidity ^0.5.12;
          
          
          
          
          
          
          
          
          
          
          
          
          
          
          
          
          
          contract WTON is DSMath, ReentrancyGuard, Ownable, ERC20Mintable, ERC20Burnable, ERC20Detailed, SeigToken, OnApprove {
            using SafeERC20 for ERC20Mintable;
          
            ERC20Mintable public ton;
          
            constructor (
              ERC20Mintable _ton
            )
              public
              ERC20Detailed("Wrapped TON", "WTON", 27)
            {
              require(ERC20Detailed(address(_ton)).decimals() == 18, "WTON: decimals of TON must be 18");
              ton = _ton;
            }
          
            //////////////////////
            // TON Approve callback
            //////////////////////
          
            function onApprove(
              address owner,
              address spender,
              uint256 tonAmount,
              bytes calldata data
            ) external returns (bool) {
              require(msg.sender == address(ton), "WTON: only accept TON approve callback");
          
              // swap owner's TON to WTON
              _swapFromTON(owner, owner, tonAmount);
          
              uint256 wtonAmount = _toRAY(tonAmount);
              (address depositManager, address layer2) = _decodeTONApproveData(data);
          
              // approve WTON to DepositManager
              _approve(owner, depositManager, wtonAmount);
          
              // call DepositManager.onApprove to deposit WTON
              bytes memory depositManagerOnApproveData = _encodeDepositManagerOnApproveData(layer2);
              _callOnApprove(owner, depositManager, wtonAmount, depositManagerOnApproveData);
          
              return true;
            }
          
            /**
             * @dev data is 64 bytes of 2 addresses in left-padded 32 bytes
             */
            function _decodeTONApproveData(
              bytes memory data
            ) internal pure returns (address depositManager, address layer2) {
              require(data.length == 0x40);
          
              assembly {
                depositManager := mload(add(data, 0x20))
                layer2 := mload(add(data, 0x40))
              }
            }
          
            function _encodeDepositManagerOnApproveData(
              address layer2
            ) internal pure returns (bytes memory data) {
              data = new bytes(0x20);
          
              assembly {
                mstore(add(data, 0x20), layer2)
              }
            }
          
          
            //////////////////////
            // Override ERC20 functions
            //////////////////////
          
            function burnFrom(address account, uint256 amount) public {
              if (isMinter(msg.sender)) {
                _burn(account, amount);
                return;
              }
          
              super.burnFrom(account, amount);
            }
          
            //////////////////////
            // Swap functions
            //////////////////////
          
            /**
             * @dev swap WTON to TON
             */
            function swapToTON(uint256 wtonAmount) public nonReentrant returns (bool) {
              return _swapToTON(msg.sender, msg.sender, wtonAmount);
            }
          
            /**
             * @dev swap TON to WTON
             */
            function swapFromTON(uint256 tonAmount) public nonReentrant returns (bool) {
              return _swapFromTON(msg.sender, msg.sender, tonAmount);
            }
          
            /**
             * @dev swap WTON to TON, and transfer TON
             * NOTE: TON's transfer event's `from` argument is not `msg.sender` but `WTON` address.
             */
            function swapToTONAndTransfer(address to, uint256 wtonAmount) public nonReentrant returns (bool) {
              return _swapToTON(to, msg.sender, wtonAmount);
            }
          
            /**
             * @dev swap TON to WTON, and transfer WTON
             */
            function swapFromTONAndTransfer(address to, uint256 tonAmount) public nonReentrant returns (bool) {
              return _swapFromTON(msg.sender, to, tonAmount);
            }
          
            function renounceTonMinter() external onlyOwner {
              ton.renounceMinter();
            }
          
            //////////////////////
            // Internal functions
            //////////////////////
          
            function _swapToTON(address tonAccount, address wtonAccount, uint256 wtonAmount) internal returns (bool) {
              _burn(wtonAccount, wtonAmount);
          
              // mint TON if WTON contract has not enough TON to transfer
              uint256 tonAmount = _toWAD(wtonAmount);
              uint256 tonBalance = ton.balanceOf(address(this));
              if (tonBalance < tonAmount) {
                ton.mint(address(this), tonAmount.sub(tonBalance));
              }
          
              ton.safeTransfer(tonAccount, tonAmount);
              return true;
            }
          
            function _swapFromTON(address tonAccount, address wtonAccount, uint256 tonAmount) internal returns (bool) {
              _mint(wtonAccount, _toRAY(tonAmount));
              ton.safeTransferFrom(tonAccount, address(this), tonAmount);
              return true;
            }
          
            /**
             * @dev transform WAD to RAY
             */
            function _toRAY(uint256 v) internal pure returns (uint256) {
              return v * 10 ** 9;
            }
          
            /**
             * @dev transform RAY to WAD
             */
            function _toWAD(uint256 v) internal pure returns (uint256) {
              return v / 10 ** 9;
            }
          }

          File 3 of 8: DepositManager
          // File: openzeppelin-solidity/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-solidity/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 {
                  address msgSender = _msgSender();
                  _owner = msgSender;
                  emit OwnershipTransferred(address(0), msgSender);
              }
          
              /**
               * @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-solidity/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-solidity/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);
          
              /**
               * @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-solidity/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.
               *
               * [IMPORTANT]
               * ====
               * It is unsafe to assume that an address for which this function returns
               * false is an externally-owned account (EOA) and not a contract.
               *
               * Among others, `isContract` will return false for the following 
               * types of addresses:
               *
               *  - an externally-owned account
               *  - a contract in construction
               *  - an address where a contract will be created
               *  - an address where a contract lived, but was destroyed
               * ====
               */
              function isContract(address account) internal view returns (bool) {
                  // 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 != accountHash && codehash != 0x0);
              }
          
              /**
               * @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-solidity/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: openzeppelin-solidity/contracts/introspection/IERC165.sol
          
          pragma solidity ^0.5.0;
          
          /**
           * @dev Interface of the ERC165 standard, as defined in the
           * https://eips.ethereum.org/EIPS/eip-165[EIP].
           *
           * Implementers can declare support of contract interfaces, which can then be
           * queried by others ({ERC165Checker}).
           *
           * For an implementation, see {ERC165}.
           */
          interface IERC165 {
              /**
               * @dev Returns true if this contract implements the interface defined by
               * `interfaceId`. See the corresponding
               * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
               * to learn more about how these ids are created.
               *
               * This function call must use less than 30 000 gas.
               */
              function supportsInterface(bytes4 interfaceId) external view returns (bool);
          }
          
          // File: openzeppelin-solidity/contracts/introspection/ERC165.sol
          
          pragma solidity ^0.5.0;
          
          
          /**
           * @dev Implementation of the {IERC165} interface.
           *
           * Contracts may inherit from this and call {_registerInterface} to declare
           * their support of an interface.
           */
          contract ERC165 is IERC165 {
              /*
               * bytes4(keccak256('supportsInterface(bytes4)')) == 0x01ffc9a7
               */
              bytes4 private constant _INTERFACE_ID_ERC165 = 0x01ffc9a7;
          
              /**
               * @dev Mapping of interface ids to whether or not it's supported.
               */
              mapping(bytes4 => bool) private _supportedInterfaces;
          
              constructor () internal {
                  // Derived contracts need only register support for their own interfaces,
                  // we register support for ERC165 itself here
                  _registerInterface(_INTERFACE_ID_ERC165);
              }
          
              /**
               * @dev See {IERC165-supportsInterface}.
               *
               * Time complexity O(1), guaranteed to always use less than 30 000 gas.
               */
              function supportsInterface(bytes4 interfaceId) external view returns (bool) {
                  return _supportedInterfaces[interfaceId];
              }
          
              /**
               * @dev Registers the contract as an implementer of the interface defined by
               * `interfaceId`. Support of the actual ERC165 interface is automatic and
               * registering its interface id is not required.
               *
               * See {IERC165-supportsInterface}.
               *
               * Requirements:
               *
               * - `interfaceId` cannot be the ERC165 invalid interface (`0xffffffff`).
               */
              function _registerInterface(bytes4 interfaceId) internal {
                  require(interfaceId != 0xffffffff, "ERC165: invalid interface id");
                  _supportedInterfaces[interfaceId] = true;
              }
          }
          
          // File: contracts/Layer2I.sol
          
          pragma solidity ^0.5.12;
          
          interface Layer2I {
            function operator() external view returns (address);
            function isLayer2() external view returns (bool);
            function currentFork() external view returns (uint);
            function lastEpoch(uint forkNumber) external view returns (uint);
            function changeOperator(address _operator) external;
          }
          
          // File: contracts/stake/interfaces/DepositManagerI.sol
          
          pragma solidity ^0.5.12;
          
          
          interface DepositManagerI {
            function owner() external view returns (address);
            function wton() external view returns (address);
            function registry() external view returns (address);
            function seigManager() external view returns (address);
          
            function accStaked(address layer2, address account) external view returns (uint256 wtonAmount);
            function accStakedLayer2(address layer2) external view returns (uint256 wtonAmount);
            function accStakedAccount(address account) external view returns (uint256 wtonAmount);
          
            function pendingUnstaked(address layer2, address account) external view returns (uint256 wtonAmount);
            function pendingUnstakedLayer2(address layer2) external view returns (uint256 wtonAmount);
            function pendingUnstakedAccount(address account) external view returns (uint256 wtonAmount);
          
            function accUnstaked(address layer2, address account) external view returns (uint256 wtonAmount);
            function accUnstakedLayer2(address layer2) external view returns (uint256 wtonAmount);
            function accUnstakedAccount(address account) external view returns (uint256 wtonAmount);
          
          
            function withdrawalRequestIndex(address layer2, address account) external view returns (uint256 index);
            function withdrawalRequest(address layer2, address account, uint256 index) external view returns (uint128 withdrawableBlockNumber, uint128 amount, bool processed );
          
            function WITHDRAWAL_DELAY() external view returns (uint256);
          
            function setSeigManager(address seigManager) external;
            function deposit(address layer2, uint256 amount) external returns (bool);
            function requestWithdrawal(address layer2, uint256 amount) external returns (bool);
            function processRequest(address layer2) external returns (bool);
            function requestWithdrawalAll(address layer2) external returns (bool);
            function processRequests(address layer2, uint256 n) external returns (bool);
          
            function numRequests(address layer2, address account) external view returns (uint256);
            function numPendingRequests(address layer2, address account) external view returns (uint256);
          
            function slash(address layer2, address recipient, uint256 amount) external returns (bool);
          }
          
          // File: contracts/stake/interfaces/Layer2RegistryI.sol
          
          pragma solidity ^0.5.12;
          
          
          interface Layer2RegistryI {
            function layer2s(address layer2) external view returns (bool);
          
            function register(address layer2) external returns (bool);
            function numLayer2s() external view returns (uint256);
            function layer2ByIndex(uint256 index) external view returns (address);
          
            function deployCoinage(address layer2, address seigManager) external returns (bool);
            function registerAndDeployCoinage(address layer2, address seigManager) external returns (bool);
            function unregister(address layer2) external returns (bool);
          }
          
          // File: contracts/stake/interfaces/SeigManagerI.sol
          
          pragma solidity ^0.5.12;
          
          
          interface SeigManagerI {
            function registry() external view returns (address);
            function depositManager() external view returns (address);
            function ton() external view returns (address);
            function wton() external view returns (address);
            function powerton() external view returns (address);
            function tot() external view returns (address);
            function coinages(address layer2) external view returns (address);
            function commissionRates(address layer2) external view returns (uint256);
          
            function lastCommitBlock(address layer2) external view returns (uint256);
            function seigPerBlock() external view returns (uint256);
            function lastSeigBlock() external view returns (uint256);
            function pausedBlock() external view returns (uint256);
            function unpausedBlock() external view returns (uint256);
            function DEFAULT_FACTOR() external view returns (uint256);
          
            function deployCoinage(address layer2) external returns (bool);
            function setCommissionRate(address layer2, uint256 commission, bool isCommissionRateNegative) external returns (bool);
          
            function uncomittedStakeOf(address layer2, address account) external view returns (uint256);
            function stakeOf(address layer2, address account) external view returns (uint256);
            function additionalTotBurnAmount(address layer2, address account, uint256 amount) external view returns (uint256 totAmount);
          
            function onTransfer(address sender, address recipient, uint256 amount) external returns (bool);
            function updateSeigniorage() external returns (bool);
            function onDeposit(address layer2, address account, uint256 amount) external returns (bool);
            function onWithdraw(address layer2, address account, uint256 amount) external returns (bool);
          
          }
          
          // File: openzeppelin-solidity/contracts/token/ERC20/ERC20.sol
          
          pragma solidity ^0.5.0;
          
          
          
          
          /**
           * @dev Implementation of the {IERC20} interface.
           *
           * This implementation is agnostic to the way tokens are created. This means
           * that a supply mechanism has to be added in a derived contract using {_mint}.
           * For a generic mechanism see {ERC20Mintable}.
           *
           * TIP: For a detailed writeup see our guide
           * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How
           * to implement supply mechanisms].
           *
           * We have followed general OpenZeppelin guidelines: functions revert instead
           * of returning `false` on failure. This behavior is nonetheless conventional
           * and does not conflict with the expectations of ERC20 applications.
           *
           * Additionally, an {Approval} event is emitted on calls to {transferFrom}.
           * This allows applications to reconstruct the allowance for all accounts just
           * by listening to said events. Other implementations of the EIP may not emit
           * these events, as it isn't required by the specification.
           *
           * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}
           * functions have been added to mitigate the well-known issues around setting
           * allowances. See {IERC20-approve}.
           */
          contract ERC20 is Context, IERC20 {
              using SafeMath for uint256;
          
              mapping (address => uint256) private _balances;
          
              mapping (address => mapping (address => uint256)) private _allowances;
          
              uint256 private _totalSupply;
          
              /**
               * @dev See {IERC20-totalSupply}.
               */
              function totalSupply() public view returns (uint256) {
                  return _totalSupply;
              }
          
              /**
               * @dev See {IERC20-balanceOf}.
               */
              function balanceOf(address account) public view returns (uint256) {
                  return _balances[account];
              }
          
              /**
               * @dev See {IERC20-transfer}.
               *
               * Requirements:
               *
               * - `recipient` cannot be the zero address.
               * - the caller must have a balance of at least `amount`.
               */
              function transfer(address recipient, uint256 amount) public returns (bool) {
                  _transfer(_msgSender(), recipient, amount);
                  return true;
              }
          
              /**
               * @dev See {IERC20-allowance}.
               */
              function allowance(address owner, address spender) public view returns (uint256) {
                  return _allowances[owner][spender];
              }
          
              /**
               * @dev See {IERC20-approve}.
               *
               * Requirements:
               *
               * - `spender` cannot be the zero address.
               */
              function approve(address spender, uint256 amount) public returns (bool) {
                  _approve(_msgSender(), spender, amount);
                  return true;
              }
          
              /**
               * @dev See {IERC20-transferFrom}.
               *
               * Emits an {Approval} event indicating the updated allowance. This is not
               * required by the EIP. See the note at the beginning of {ERC20};
               *
               * Requirements:
               * - `sender` and `recipient` cannot be the zero address.
               * - `sender` must have a balance of at least `amount`.
               * - the caller must have allowance for `sender`'s tokens of at least
               * `amount`.
               */
              function transferFrom(address sender, address recipient, uint256 amount) public returns (bool) {
                  _transfer(sender, recipient, amount);
                  _approve(sender, _msgSender(), _allowances[sender][_msgSender()].sub(amount, "ERC20: transfer amount exceeds allowance"));
                  return true;
              }
          
              /**
               * @dev Atomically increases the allowance granted to `spender` by the caller.
               *
               * This is an alternative to {approve} that can be used as a mitigation for
               * problems described in {IERC20-approve}.
               *
               * Emits an {Approval} event indicating the updated allowance.
               *
               * Requirements:
               *
               * - `spender` cannot be the zero address.
               */
              function increaseAllowance(address spender, uint256 addedValue) public returns (bool) {
                  _approve(_msgSender(), spender, _allowances[_msgSender()][spender].add(addedValue));
                  return true;
              }
          
              /**
               * @dev Atomically decreases the allowance granted to `spender` by the caller.
               *
               * This is an alternative to {approve} that can be used as a mitigation for
               * problems described in {IERC20-approve}.
               *
               * Emits an {Approval} event indicating the updated allowance.
               *
               * Requirements:
               *
               * - `spender` cannot be the zero address.
               * - `spender` must have allowance for the caller of at least
               * `subtractedValue`.
               */
              function decreaseAllowance(address spender, uint256 subtractedValue) public returns (bool) {
                  _approve(_msgSender(), spender, _allowances[_msgSender()][spender].sub(subtractedValue, "ERC20: decreased allowance below zero"));
                  return true;
              }
          
              /**
               * @dev Moves tokens `amount` from `sender` to `recipient`.
               *
               * This is internal function is equivalent to {transfer}, and can be used to
               * e.g. implement automatic token fees, slashing mechanisms, etc.
               *
               * Emits a {Transfer} event.
               *
               * Requirements:
               *
               * - `sender` cannot be the zero address.
               * - `recipient` cannot be the zero address.
               * - `sender` must have a balance of at least `amount`.
               */
              function _transfer(address sender, address recipient, uint256 amount) internal {
                  require(sender != address(0), "ERC20: transfer from the zero address");
                  require(recipient != address(0), "ERC20: transfer to the zero address");
          
                  _balances[sender] = _balances[sender].sub(amount, "ERC20: transfer amount exceeds balance");
                  _balances[recipient] = _balances[recipient].add(amount);
                  emit Transfer(sender, recipient, amount);
              }
          
              /** @dev Creates `amount` tokens and assigns them to `account`, increasing
               * the total supply.
               *
               * Emits a {Transfer} event with `from` set to the zero address.
               *
               * Requirements
               *
               * - `to` cannot be the zero address.
               */
              function _mint(address account, uint256 amount) internal {
                  require(account != address(0), "ERC20: mint to the zero address");
          
                  _totalSupply = _totalSupply.add(amount);
                  _balances[account] = _balances[account].add(amount);
                  emit Transfer(address(0), account, amount);
              }
          
              /**
               * @dev Destroys `amount` tokens from `account`, reducing the
               * total supply.
               *
               * Emits a {Transfer} event with `to` set to the zero address.
               *
               * Requirements
               *
               * - `account` cannot be the zero address.
               * - `account` must have at least `amount` tokens.
               */
              function _burn(address account, uint256 amount) internal {
                  require(account != address(0), "ERC20: burn from the zero address");
          
                  _balances[account] = _balances[account].sub(amount, "ERC20: burn amount exceeds balance");
                  _totalSupply = _totalSupply.sub(amount);
                  emit Transfer(account, address(0), amount);
              }
          
              /**
               * @dev Sets `amount` as the allowance of `spender` over the `owner`s tokens.
               *
               * This is internal function is equivalent to `approve`, and can be used to
               * e.g. set automatic allowances for certain subsystems, etc.
               *
               * Emits an {Approval} event.
               *
               * Requirements:
               *
               * - `owner` cannot be the zero address.
               * - `spender` cannot be the zero address.
               */
              function _approve(address owner, address spender, uint256 amount) internal {
                  require(owner != address(0), "ERC20: approve from the zero address");
                  require(spender != address(0), "ERC20: approve to the zero address");
          
                  _allowances[owner][spender] = amount;
                  emit Approval(owner, spender, amount);
              }
          
              /**
               * @dev Destroys `amount` tokens from `account`.`amount` is then deducted
               * from the caller's allowance.
               *
               * See {_burn} and {_approve}.
               */
              function _burnFrom(address account, uint256 amount) internal {
                  _burn(account, amount);
                  _approve(account, _msgSender(), _allowances[account][_msgSender()].sub(amount, "ERC20: burn amount exceeds allowance"));
              }
          }
          
          // File: openzeppelin-solidity/contracts/access/Roles.sol
          
          pragma solidity ^0.5.0;
          
          /**
           * @title Roles
           * @dev Library for managing addresses assigned to a Role.
           */
          library Roles {
              struct Role {
                  mapping (address => bool) bearer;
              }
          
              /**
               * @dev Give an account access to this role.
               */
              function add(Role storage role, address account) internal {
                  require(!has(role, account), "Roles: account already has role");
                  role.bearer[account] = true;
              }
          
              /**
               * @dev Remove an account's access to this role.
               */
              function remove(Role storage role, address account) internal {
                  require(has(role, account), "Roles: account does not have role");
                  role.bearer[account] = false;
              }
          
              /**
               * @dev Check if an account has this role.
               * @return bool
               */
              function has(Role storage role, address account) internal view returns (bool) {
                  require(account != address(0), "Roles: account is the zero address");
                  return role.bearer[account];
              }
          }
          
          // File: openzeppelin-solidity/contracts/access/roles/MinterRole.sol
          
          pragma solidity ^0.5.0;
          
          
          
          contract MinterRole is Context {
              using Roles for Roles.Role;
          
              event MinterAdded(address indexed account);
              event MinterRemoved(address indexed account);
          
              Roles.Role private _minters;
          
              constructor () internal {
                  _addMinter(_msgSender());
              }
          
              modifier onlyMinter() {
                  require(isMinter(_msgSender()), "MinterRole: caller does not have the Minter role");
                  _;
              }
          
              function isMinter(address account) public view returns (bool) {
                  return _minters.has(account);
              }
          
              function addMinter(address account) public onlyMinter {
                  _addMinter(account);
              }
          
              function renounceMinter() public {
                  _removeMinter(_msgSender());
              }
          
              function _addMinter(address account) internal {
                  _minters.add(account);
                  emit MinterAdded(account);
              }
          
              function _removeMinter(address account) internal {
                  _minters.remove(account);
                  emit MinterRemoved(account);
              }
          }
          
          // File: openzeppelin-solidity/contracts/token/ERC20/ERC20Mintable.sol
          
          pragma solidity ^0.5.0;
          
          
          
          /**
           * @dev Extension of {ERC20} that adds a set of accounts with the {MinterRole},
           * which have permission to mint (create) new tokens as they see fit.
           *
           * At construction, the deployer of the contract is the only minter.
           */
          contract ERC20Mintable is ERC20, MinterRole {
              /**
               * @dev See {ERC20-_mint}.
               *
               * Requirements:
               *
               * - the caller must have the {MinterRole}.
               */
              function mint(address account, uint256 amount) public onlyMinter returns (bool) {
                  _mint(account, amount);
                  return true;
              }
          }
          
          // File: openzeppelin-solidity/contracts/token/ERC20/ERC20Burnable.sol
          
          pragma solidity ^0.5.0;
          
          
          
          /**
           * @dev Extension of {ERC20} that allows token holders to destroy both their own
           * tokens and those that they have an allowance for, in a way that can be
           * recognized off-chain (via event analysis).
           */
          contract ERC20Burnable is Context, ERC20 {
              /**
               * @dev Destroys `amount` tokens from the caller.
               *
               * See {ERC20-_burn}.
               */
              function burn(uint256 amount) public {
                  _burn(_msgSender(), amount);
              }
          
              /**
               * @dev See {ERC20-_burnFrom}.
               */
              function burnFrom(address account, uint256 amount) public {
                  _burnFrom(account, amount);
              }
          }
          
          // File: openzeppelin-solidity/contracts/token/ERC20/ERC20Detailed.sol
          
          pragma solidity ^0.5.0;
          
          
          /**
           * @dev Optional functions from the ERC20 standard.
           */
          contract ERC20Detailed is IERC20 {
              string private _name;
              string private _symbol;
              uint8 private _decimals;
          
              /**
               * @dev Sets the values for `name`, `symbol`, and `decimals`. All three of
               * these values are immutable: they can only be set once during
               * construction.
               */
              constructor (string memory name, string memory symbol, uint8 decimals) public {
                  _name = name;
                  _symbol = symbol;
                  _decimals = decimals;
              }
          
              /**
               * @dev Returns the name of the token.
               */
              function name() public view returns (string memory) {
                  return _name;
              }
          
              /**
               * @dev Returns the symbol of the token, usually a shorter version of the
               * name.
               */
              function symbol() public view returns (string memory) {
                  return _symbol;
              }
          
              /**
               * @dev Returns the number of decimals used to get its user representation.
               * For example, if `decimals` equals `2`, a balance of `505` tokens should
               * be displayed to a user as `5,05` (`505 / 10 ** 2`).
               *
               * Tokens usually opt for a value of 18, imitating the relationship between
               * Ether and Wei.
               *
               * NOTE: This information is only used for _display_ purposes: it in
               * no way affects any of the arithmetic of the contract, including
               * {IERC20-balanceOf} and {IERC20-transfer}.
               */
              function decimals() public view returns (uint8) {
                  return _decimals;
              }
          }
          
          // File: openzeppelin-solidity/contracts/utils/ReentrancyGuard.sol
          
          pragma solidity ^0.5.0;
          
          /**
           * @dev Contract module that helps prevent reentrant calls to a function.
           *
           * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
           * available, which can be applied to functions to make sure there are no nested
           * (reentrant) calls to them.
           *
           * Note that because there is a single `nonReentrant` guard, functions marked as
           * `nonReentrant` may not call one another. This can be worked around by making
           * those functions `private`, and then adding `external` `nonReentrant` entry
           * points to them.
           *
           * TIP: If you would like to learn more about reentrancy and alternative ways
           * to protect against it, check out our blog post
           * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
           *
           * _Since v2.5.0:_ this module is now much more gas efficient, given net gas
           * metering changes introduced in the Istanbul hardfork.
           */
          contract ReentrancyGuard {
              bool private _notEntered;
          
              constructor () internal {
                  // Storing an initial non-zero value makes deployment a bit more
                  // expensive, but in exchange the refund on every call to nonReentrant
                  // will be lower in amount. Since refunds are capped to a percetange of
                  // the total transaction's gas, it is best to keep them low in cases
                  // like this one, to increase the likelihood of the full refund coming
                  // into effect.
                  _notEntered = true;
              }
          
              /**
               * @dev Prevents a contract from calling itself, directly or indirectly.
               * Calling a `nonReentrant` function from another `nonReentrant`
               * function is not supported. It is possible to prevent this from happening
               * by making the `nonReentrant` function external, and make it call a
               * `private` function that does the actual work.
               */
              modifier nonReentrant() {
                  // On the first call to nonReentrant, _notEntered will be true
                  require(_notEntered, "ReentrancyGuard: reentrant call");
          
                  // Any calls to nonReentrant after this point will fail
                  _notEntered = false;
          
                  _;
          
                  // By storing the original value once again, a refund is triggered (see
                  // https://eips.ethereum.org/EIPS/eip-2200)
                  _notEntered = true;
              }
          }
          
          // File: openzeppelin-solidity/contracts/introspection/ERC165Checker.sol
          
          pragma solidity ^0.5.10;
          
          /**
           * @dev Library used to query support of an interface declared via {IERC165}.
           *
           * Note that these functions return the actual result of the query: they do not
           * `revert` if an interface is not supported. It is up to the caller to decide
           * what to do in these cases.
           */
          library ERC165Checker {
              // As per the EIP-165 spec, no interface should ever match 0xffffffff
              bytes4 private constant _INTERFACE_ID_INVALID = 0xffffffff;
          
              /*
               * bytes4(keccak256('supportsInterface(bytes4)')) == 0x01ffc9a7
               */
              bytes4 private constant _INTERFACE_ID_ERC165 = 0x01ffc9a7;
          
              /**
               * @dev Returns true if `account` supports the {IERC165} interface,
               */
              function _supportsERC165(address account) internal view returns (bool) {
                  // Any contract that implements ERC165 must explicitly indicate support of
                  // InterfaceId_ERC165 and explicitly indicate non-support of InterfaceId_Invalid
                  return _supportsERC165Interface(account, _INTERFACE_ID_ERC165) &&
                      !_supportsERC165Interface(account, _INTERFACE_ID_INVALID);
              }
          
              /**
               * @dev Returns true if `account` supports the interface defined by
               * `interfaceId`. Support for {IERC165} itself is queried automatically.
               *
               * See {IERC165-supportsInterface}.
               */
              function _supportsInterface(address account, bytes4 interfaceId) internal view returns (bool) {
                  // query support of both ERC165 as per the spec and support of _interfaceId
                  return _supportsERC165(account) &&
                      _supportsERC165Interface(account, interfaceId);
              }
          
              /**
               * @dev Returns true if `account` supports all the interfaces defined in
               * `interfaceIds`. Support for {IERC165} itself is queried automatically.
               *
               * Batch-querying can lead to gas savings by skipping repeated checks for
               * {IERC165} support.
               *
               * See {IERC165-supportsInterface}.
               */
              function _supportsAllInterfaces(address account, bytes4[] memory interfaceIds) internal view returns (bool) {
                  // query support of ERC165 itself
                  if (!_supportsERC165(account)) {
                      return false;
                  }
          
                  // query support of each interface in _interfaceIds
                  for (uint256 i = 0; i < interfaceIds.length; i++) {
                      if (!_supportsERC165Interface(account, interfaceIds[i])) {
                          return false;
                      }
                  }
          
                  // all interfaces supported
                  return true;
              }
          
              /**
               * @notice Query if a contract implements an interface, does not check ERC165 support
               * @param account The address of the contract to query for support of an interface
               * @param interfaceId The interface identifier, as specified in ERC-165
               * @return true if the contract at account indicates support of the interface with
               * identifier interfaceId, false otherwise
               * @dev Assumes that account contains a contract that supports ERC165, otherwise
               * the behavior of this method is undefined. This precondition can be checked
               * with the `supportsERC165` method in this library.
               * Interface identification is specified in ERC-165.
               */
              function _supportsERC165Interface(address account, bytes4 interfaceId) private view returns (bool) {
                  // success determines whether the staticcall succeeded and result determines
                  // whether the contract at account indicates support of _interfaceId
                  (bool success, bool result) = _callERC165SupportsInterface(account, interfaceId);
          
                  return (success && result);
              }
          
              /**
               * @notice Calls the function with selector 0x01ffc9a7 (ERC165) and suppresses throw
               * @param account The address of the contract to query for support of an interface
               * @param interfaceId The interface identifier, as specified in ERC-165
               * @return success true if the STATICCALL succeeded, false otherwise
               * @return result true if the STATICCALL succeeded and the contract at account
               * indicates support of the interface with identifier interfaceId, false otherwise
               */
              function _callERC165SupportsInterface(address account, bytes4 interfaceId)
                  private
                  view
                  returns (bool, bool)
              {
                  bytes memory encodedParams = abi.encodeWithSelector(_INTERFACE_ID_ERC165, interfaceId);
                  (bool success, bytes memory result) = account.staticcall.gas(30000)(encodedParams);
                  if (result.length < 32) return (false, false);
                  return (success, abi.decode(result, (bool)));
              }
          }
          
          // File: coinage-token/contracts/lib/DSMath.sol
          
          // https://github.com/dapphub/ds-math/blob/de45767/src/math.sol
          /// math.sol -- mixin for inline numerical wizardry
          
          // This program is free software: you can redistribute it and/or modify
          // it under the terms of the GNU General Public License as published by
          // the Free Software Foundation, either version 3 of the License, or
          // (at your option) any later version.
          
          // This program is distributed in the hope that it will be useful,
          // but WITHOUT ANY WARRANTY; without even the implied warranty of
          // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
          // GNU General Public License for more details.
          
          // You should have received a copy of the GNU General Public License
          // along with this program.  If not, see <http://www.gnu.org/licenses/>.
          
          pragma solidity >0.4.13;
          
          contract DSMath {
            function add(uint x, uint y) internal pure returns (uint z) {
              require((z = x + y) >= x, "ds-math-add-overflow");
            }
            function sub(uint x, uint y) internal pure returns (uint z) {
              require((z = x - y) <= x, "ds-math-sub-underflow");
            }
            function mul(uint x, uint y) internal pure returns (uint z) {
              require(y == 0 || (z = x * y) / y == x, "ds-math-mul-overflow");
            }
          
            function min(uint x, uint y) internal pure returns (uint z) {
              return x <= y ? x : y;
            }
            function max(uint x, uint y) internal pure returns (uint z) {
              return x >= y ? x : y;
            }
            function imin(int x, int y) internal pure returns (int z) {
              return x <= y ? x : y;
            }
            function imax(int x, int y) internal pure returns (int z) {
              return x >= y ? x : y;
            }
          
            uint constant WAD = 10 ** 18;
            uint constant RAY = 10 ** 27;
          
            function wmul(uint x, uint y) internal pure returns (uint z) {
              z = add(mul(x, y), WAD / 2) / WAD;
            }
            function rmul(uint x, uint y) internal pure returns (uint z) {
              z = add(mul(x, y), RAY / 2) / RAY;
            }
            function wdiv(uint x, uint y) internal pure returns (uint z) {
              z = add(mul(x, WAD), y / 2) / y;
            }
            function rdiv(uint x, uint y) internal pure returns (uint z) {
              z = add(mul(x, RAY), y / 2) / y;
            }
          
            // This famous algorithm is called "exponentiation by squaring"
            // and calculates x^n with x as fixed-point and n as regular unsigned.
            //
            // It's O(log n), instead of O(n) for naive repeated multiplication.
            //
            // These facts are why it works:
            //
            //  If n is even, then x^n = (x^2)^(n/2).
            //  If n is odd,  then x^n = x * x^(n-1),
            //   and applying the equation for even x gives
            //  x^n = x * (x^2)^((n-1) / 2).
            //
            //  Also, EVM division is flooring and
            //  floor[(n-1) / 2] = floor[n / 2].
            //
            function wpow(uint x, uint n) internal pure returns (uint z) {
              z = n % 2 != 0 ? x : WAD;
          
              for (n /= 2; n != 0; n /= 2) {
                x = wmul(x, x);
          
                if (n % 2 != 0) {
                  z = wmul(z, x);
                }
              }
            }
          
            function rpow(uint x, uint n) internal pure returns (uint z) {
              z = n % 2 != 0 ? x : RAY;
          
              for (n /= 2; n != 0; n /= 2) {
                x = rmul(x, x);
          
                if (n % 2 != 0) {
                  z = rmul(z, x);
                }
              }
            }
          }
          
          // File: contracts/stake/tokens/OnApprove.sol
          
          pragma solidity ^0.5.12;
          
          
          contract OnApprove is ERC165 {
            constructor() public {
              _registerInterface(OnApprove(this).onApprove.selector);
            }
          
            function onApprove(address owner, address spender, uint256 amount, bytes calldata data) external returns (bool);
          }
          
          // File: contracts/stake/tokens/ERC20OnApprove.sol
          
          pragma solidity ^0.5.12;
          
          
          
          
          
          contract ERC20OnApprove is ERC20 {
            function approveAndCall(address spender, uint256 amount, bytes memory data) public returns (bool) {
              require(approve(spender, amount));
              _callOnApprove(msg.sender, spender, amount, data);
              return true;
            }
          
            function _callOnApprove(address owner, address spender, uint256 amount, bytes memory data) internal {
              bytes4 onApproveSelector = OnApprove(spender).onApprove.selector;
          
              require(ERC165Checker._supportsInterface(spender, onApproveSelector),
                "ERC20OnApprove: spender doesn't support onApprove");
          
              (bool ok, bytes memory res) = spender.call(
                abi.encodeWithSelector(
                  onApproveSelector,
                  owner,
                  spender,
                  amount,
                  data
                )
              );
          
              // check if low-level call reverted or not
              require(ok, string(res));
          
              assembly {
                ok := mload(add(res, 0x20))
              }
          
              // check if OnApprove.onApprove returns true or false
              require(ok, "ERC20OnApprove: failed to call onApprove");
            }
          
          }
          
          // File: contracts/stake/tokens/AuthController.sol
          
          pragma solidity ^0.5.12;
          
          
          
          interface MinterRoleRenounceTarget {
            function renounceMinter() external;
          }
          
          interface PauserRoleRenounceTarget {
            function renouncePauser() external;
          }
          
          interface OwnableTarget {
            function renounceOwnership() external;
            function transferOwnership(address newOwner) external;
          }
          
          contract AuthController is Ownable {
            function renounceMinter(address target) public onlyOwner {
              MinterRoleRenounceTarget(target).renounceMinter();
            }
          
            function renouncePauser(address target) public onlyOwner {
              PauserRoleRenounceTarget(target).renouncePauser();
            }
          
            function renounceOwnership(address target) public onlyOwner {
              OwnableTarget(target).renounceOwnership();
            }
          
            function transferOwnership(address target, address newOwner) public onlyOwner {
              OwnableTarget(target).transferOwnership(newOwner);
            }
          }
          
          // File: contracts/stake/tokens/SeigToken.sol
          
          pragma solidity ^0.5.12;
          
          
          
          
          
          
          
          contract SeigToken is ERC20, Ownable, ERC20OnApprove, AuthController {
            SeigManagerI public seigManager;
            bool public callbackEnabled;
          
            function enableCallback(bool _callbackEnabled) external onlyOwner {
              callbackEnabled = _callbackEnabled;
            }
          
            function setSeigManager(SeigManagerI _seigManager) external onlyOwner {
              seigManager = _seigManager;
            }
          
            //////////////////////
            // Override ERC20 functions
            //////////////////////
          
            function transferFrom(address sender, address recipient, uint256 amount) public returns (bool) {
              return super.transferFrom(sender, recipient, amount);
            }
          
            function _transfer(address sender, address recipient, uint256 amount) internal {
              super._transfer(sender, recipient, amount);
              if (callbackEnabled && address(seigManager) != address(0)) {
                require(seigManager.onTransfer(sender, recipient, amount));
              }
            }
          
            function _mint(address account, uint256 amount) internal {
              super._mint(account, amount);
              if (callbackEnabled && address(seigManager) != address(0)) {
                require(seigManager.onTransfer(address(0), account, amount));
              }
            }
          
            function _burn(address account, uint256 amount) internal {
              super._burn(account, amount);
              if (callbackEnabled && address(seigManager) != address(0)) {
                require(seigManager.onTransfer(account, address(0), amount));
              }
            }
          }
          
          // File: contracts/stake/tokens/WTON.sol
          
          pragma solidity ^0.5.12;
          
          
          
          
          
          
          
          
          
          
          
          
          
          
          
          
          
          contract WTON is DSMath, ReentrancyGuard, Ownable, ERC20Mintable, ERC20Burnable, ERC20Detailed, SeigToken, OnApprove {
            using SafeERC20 for ERC20Mintable;
          
            ERC20Mintable public ton;
          
            constructor (
              ERC20Mintable _ton
            )
              public
              ERC20Detailed("Wrapped TON", "WTON", 27)
            {
              require(ERC20Detailed(address(_ton)).decimals() == 18, "WTON: decimals of TON must be 18");
              ton = _ton;
            }
          
            //////////////////////
            // TON Approve callback
            //////////////////////
          
            function onApprove(
              address owner,
              address spender,
              uint256 tonAmount,
              bytes calldata data
            ) external returns (bool) {
              require(msg.sender == address(ton), "WTON: only accept TON approve callback");
          
              // swap owner's TON to WTON
              _swapFromTON(owner, owner, tonAmount);
          
              uint256 wtonAmount = _toRAY(tonAmount);
              (address depositManager, address layer2) = _decodeTONApproveData(data);
          
              // approve WTON to DepositManager
              _approve(owner, depositManager, wtonAmount);
          
              // call DepositManager.onApprove to deposit WTON
              bytes memory depositManagerOnApproveData = _encodeDepositManagerOnApproveData(layer2);
              _callOnApprove(owner, depositManager, wtonAmount, depositManagerOnApproveData);
          
              return true;
            }
          
            /**
             * @dev data is 64 bytes of 2 addresses in left-padded 32 bytes
             */
            function _decodeTONApproveData(
              bytes memory data
            ) internal pure returns (address depositManager, address layer2) {
              require(data.length == 0x40);
          
              assembly {
                depositManager := mload(add(data, 0x20))
                layer2 := mload(add(data, 0x40))
              }
            }
          
            function _encodeDepositManagerOnApproveData(
              address layer2
            ) internal pure returns (bytes memory data) {
              data = new bytes(0x20);
          
              assembly {
                mstore(add(data, 0x20), layer2)
              }
            }
          
          
            //////////////////////
            // Override ERC20 functions
            //////////////////////
          
            function burnFrom(address account, uint256 amount) public {
              if (isMinter(msg.sender)) {
                _burn(account, amount);
                return;
              }
          
              super.burnFrom(account, amount);
            }
          
            //////////////////////
            // Swap functions
            //////////////////////
          
            /**
             * @dev swap WTON to TON
             */
            function swapToTON(uint256 wtonAmount) public nonReentrant returns (bool) {
              return _swapToTON(msg.sender, msg.sender, wtonAmount);
            }
          
            /**
             * @dev swap TON to WTON
             */
            function swapFromTON(uint256 tonAmount) public nonReentrant returns (bool) {
              return _swapFromTON(msg.sender, msg.sender, tonAmount);
            }
          
            /**
             * @dev swap WTON to TON, and transfer TON
             * NOTE: TON's transfer event's `from` argument is not `msg.sender` but `WTON` address.
             */
            function swapToTONAndTransfer(address to, uint256 wtonAmount) public nonReentrant returns (bool) {
              return _swapToTON(to, msg.sender, wtonAmount);
            }
          
            /**
             * @dev swap TON to WTON, and transfer WTON
             */
            function swapFromTONAndTransfer(address to, uint256 tonAmount) public nonReentrant returns (bool) {
              return _swapFromTON(msg.sender, to, tonAmount);
            }
          
            function renounceTonMinter() external onlyOwner {
              ton.renounceMinter();
            }
          
            //////////////////////
            // Internal functions
            //////////////////////
          
            function _swapToTON(address tonAccount, address wtonAccount, uint256 wtonAmount) internal returns (bool) {
              _burn(wtonAccount, wtonAmount);
          
              // mint TON if WTON contract has not enough TON to transfer
              uint256 tonAmount = _toWAD(wtonAmount);
              uint256 tonBalance = ton.balanceOf(address(this));
              if (tonBalance < tonAmount) {
                ton.mint(address(this), tonAmount.sub(tonBalance));
              }
          
              ton.safeTransfer(tonAccount, tonAmount);
              return true;
            }
          
            function _swapFromTON(address tonAccount, address wtonAccount, uint256 tonAmount) internal returns (bool) {
              _mint(wtonAccount, _toRAY(tonAmount));
              ton.safeTransferFrom(tonAccount, address(this), tonAmount);
              return true;
            }
          
            /**
             * @dev transform WAD to RAY
             */
            function _toRAY(uint256 v) internal pure returns (uint256) {
              return v * 10 ** 9;
            }
          
            /**
             * @dev transform RAY to WAD
             */
            function _toWAD(uint256 v) internal pure returns (uint256) {
              return v / 10 ** 9;
            }
          }
          
          // File: contracts/stake/managers/DepositManager.sol
          
          pragma solidity ^0.5.12;
          
          
          
          
          
          
          
          
          
          
          
          
          // TODO: add events
          // TODO: check deposit/withdraw WTON amount (1e27)
          
          /**
           * @dev DepositManager manages WTON deposit and withdrawal from operator and WTON holders.
           */
          contract DepositManager is Ownable, ERC165, OnApprove {
            using SafeMath for uint256;
            using SafeERC20 for WTON;
          
            ////////////////////
            // Storage - contracts
            ////////////////////
          
            WTON internal _wton;
            Layer2RegistryI internal _registry;
            SeigManagerI internal _seigManager;
          
            ////////////////////
            // Storage - token amount
            ////////////////////
          
            // accumulated staked amount
            // layer2 => msg.sender => wton amount
            mapping (address => mapping (address => uint256)) internal _accStaked;
            // layer2 => wton amount
            mapping (address => uint256) internal _accStakedLayer2;
            // msg.sender => wton amount
            mapping (address => uint256) internal _accStakedAccount;
          
            // pending unstaked amount
            // layer2 => msg.sender => wton amount
            mapping (address => mapping (address => uint256)) internal _pendingUnstaked;
            // layer2 => wton amount
            mapping (address => uint256) internal _pendingUnstakedLayer2;
            // msg.sender => wton amount
            mapping (address => uint256) internal _pendingUnstakedAccount;
          
            // accumulated unstaked amount
            // layer2 => msg.sender => wton amount
            mapping (address => mapping (address => uint256)) internal _accUnstaked;
            // layer2 => wton amount
            mapping (address => uint256) internal _accUnstakedLayer2;
            // msg.sender => wton amount
            mapping (address => uint256) internal _accUnstakedAccount;
          
            // layer2 => msg.sender => withdrawal requests
            mapping (address => mapping (address => WithdrawalReqeust[])) internal _withdrawalRequests;
          
            // layer2 => msg.sender => index
            mapping (address => mapping (address => uint256)) internal _withdrawalRequestIndex;
          
            ////////////////////
            // Storage - configuration / ERC165 interfaces
            ////////////////////
          
            // withdrawal delay in block number
            // @TODO: change delay unit to CYCLE?
            uint256 public globalWithdrawalDelay;
            mapping (address => uint256) public withdrawalDelay;
          
            struct WithdrawalReqeust {
              uint128 withdrawableBlockNumber;
              uint128 amount;
              bool processed;
            }
          
            ////////////////////
            // Modifiers
            ////////////////////
          
            modifier onlyLayer2(address layer2) {
              require(_registry.layer2s(layer2));
              _;
            }
          
            modifier onlySeigManager() {
              require(msg.sender == address(_seigManager));
              _;
            }
          
            ////////////////////
            // Events
            ////////////////////
          
            event Deposited(address indexed layer2, address depositor, uint256 amount);
            event WithdrawalRequested(address indexed layer2, address depositor, uint256 amount);
            event WithdrawalProcessed(address indexed layer2, address depositor, uint256 amount);
          
            ////////////////////
            // Constructor
            ////////////////////
          
            constructor (
              WTON wton,
              Layer2RegistryI registry,
              uint256 globalWithdrawalDelay_
            ) public {
              _wton = wton;
              _registry = registry;
              globalWithdrawalDelay = globalWithdrawalDelay_;
            }
          
            ////////////////////
            // SeiManager function
            ////////////////////
          
            function setSeigManager(SeigManagerI seigManager) external onlyOwner {
              _seigManager = seigManager;
            }
          
            ////////////////////
            // ERC20 Approve callback
            ////////////////////
          
            function onApprove(
              address owner,
              address spender,
              uint256 amount,
              bytes calldata data
            ) external returns (bool) {
              require(msg.sender == address(_wton), "DepositManager: only accept WTON approve callback");
          
              address layer2 = _decodeDepositManagerOnApproveData(data);
              require(_deposit(layer2, owner, amount));
          
              return true;
            }
          
            function _decodeDepositManagerOnApproveData(
              bytes memory data
            ) internal pure returns (address layer2) {
              require(data.length == 0x20);
          
              assembly {
                layer2 := mload(add(data, 0x20))
              }
            }
          
            ////////////////////
            // Deposit function
            ////////////////////
          
            /**
             * @dev deposit `amount` WTON in RAY
             */
          
            function deposit(address layer2, uint256 amount) external returns (bool) {
              require(_deposit(layer2, msg.sender, amount));
            }
          
            function _deposit(address layer2, address account, uint256 amount) internal onlyLayer2(layer2) returns (bool) {
              _accStaked[layer2][account] = _accStaked[layer2][account].add(amount);
              _accStakedLayer2[layer2] = _accStakedLayer2[layer2].add(amount);
              _accStakedAccount[account] = _accStakedAccount[account].add(amount);
          
              _wton.safeTransferFrom(account, address(this), amount);
          
              emit Deposited(layer2, account, amount);
          
              require(_seigManager.onDeposit(layer2, account, amount));
          
              return true;
            }
          
            ////////////////////
            // Re-deposit function
            ////////////////////
          
            /**
             * @dev re-deposit pending requests in the pending queue
             */
          
            function redeposit(address layer2) external returns (bool) {
              uint256 i = _withdrawalRequestIndex[layer2][msg.sender];
              require(_redeposit(layer2, i, 1));
            }
          
            function redepositMulti(address layer2, uint256 n) external returns (bool) {
              uint256 i = _withdrawalRequestIndex[layer2][msg.sender];
              require(_redeposit(layer2, i, n));
            }
          
            function _redeposit(address layer2, uint256 i, uint256 n) internal onlyLayer2(layer2) returns (bool) {
              uint256 accAmount;
          
              require(_withdrawalRequests[layer2][msg.sender].length > 0, "DepositManager: no request");
              require(_withdrawalRequests[layer2][msg.sender].length - i >= n, "DepositManager: n exceeds num of pending requests");
          
              uint256 e = i + n;
              for (; i < e; i++) {
                WithdrawalReqeust storage r = _withdrawalRequests[layer2][msg.sender][i];
                uint256 amount = r.amount;
          
                require(!r.processed, "DepositManager: pending request already processed");
                require(amount > 0, "DepositManager: no valid pending request");
          
                accAmount = accAmount.add(amount);
                r.processed = true;
              }
          
          
              // deposit-related storages
              _accStaked[layer2][msg.sender] = _accStaked[layer2][msg.sender].add(accAmount);
              _accStakedLayer2[layer2] = _accStakedLayer2[layer2].add(accAmount);
              _accStakedAccount[msg.sender] = _accStakedAccount[msg.sender].add(accAmount);
          
              // withdrawal-related storages
              _pendingUnstaked[layer2][msg.sender] = _pendingUnstaked[layer2][msg.sender].sub(accAmount);
              _pendingUnstakedLayer2[layer2] = _pendingUnstakedLayer2[layer2].sub(accAmount);
              _pendingUnstakedAccount[msg.sender] = _pendingUnstakedAccount[msg.sender].sub(accAmount);
          
              _withdrawalRequestIndex[layer2][msg.sender] += n;
          
              emit Deposited(layer2, msg.sender, accAmount);
          
              require(_seigManager.onDeposit(layer2, msg.sender, accAmount));
          
              return true;
            }
          
            ////////////////////
            // Slash functions
            ////////////////////
          
            function slash(address layer2, address recipient, uint256 amount) external onlySeigManager returns (bool) {
              //return _wton.transferFrom(owner, recipient, amount);
            }
          
            ////////////////////
            // Setter
            ////////////////////
          
            function setGlobalWithdrawalDelay(uint256 globalWithdrawalDelay_) external onlyOwner {
              globalWithdrawalDelay = globalWithdrawalDelay_;
            }
          
            function setWithdrawalDelay(address l2chain, uint256 withdrawalDelay_) external {
              require(_isOperator(l2chain, msg.sender));
              withdrawalDelay[l2chain] = withdrawalDelay_;
            }
          
            ////////////////////
            // Withdrawal functions
            ////////////////////
          
            function requestWithdrawal(address layer2, uint256 amount) external returns (bool) {
              return _requestWithdrawal(layer2, amount);
            }
          
            function _requestWithdrawal(address layer2, uint256 amount) internal onlyLayer2(layer2) returns (bool) {
              require(amount > 0, "DepositManager: amount must not be zero");
          
              uint256 delay = globalWithdrawalDelay > withdrawalDelay[layer2] ? globalWithdrawalDelay : withdrawalDelay[layer2];
              _withdrawalRequests[layer2][msg.sender].push(WithdrawalReqeust({
                withdrawableBlockNumber: uint128(block.number + delay),
                amount: uint128(amount),
                processed: false
              }));
          
              _pendingUnstaked[layer2][msg.sender] = _pendingUnstaked[layer2][msg.sender].add(amount);
              _pendingUnstakedLayer2[layer2] = _pendingUnstakedLayer2[layer2].add(amount);
              _pendingUnstakedAccount[msg.sender] = _pendingUnstakedAccount[msg.sender].add(amount);
          
              emit WithdrawalRequested(layer2, msg.sender, amount);
          
              require(_seigManager.onWithdraw(layer2, msg.sender, amount));
          
              return true;
            }
          
            function processRequest(address layer2, bool receiveTON) external returns (bool) {
              return _processRequest(layer2, receiveTON);
            }
          
            function _processRequest(address layer2, bool receiveTON) internal returns (bool) {
              uint256 index = _withdrawalRequestIndex[layer2][msg.sender];
              require(_withdrawalRequests[layer2][msg.sender].length > index, "DepositManager: no request to process");
          
              WithdrawalReqeust storage r = _withdrawalRequests[layer2][msg.sender][index];
          
              require(r.withdrawableBlockNumber <= block.number, "DepositManager: wait for withdrawal delay");
              r.processed = true;
          
              _withdrawalRequestIndex[layer2][msg.sender] += 1;
          
              uint256 amount = r.amount;
          
              _pendingUnstaked[layer2][msg.sender] = _pendingUnstaked[layer2][msg.sender].sub(amount);
              _pendingUnstakedLayer2[layer2] = _pendingUnstakedLayer2[layer2].sub(amount);
              _pendingUnstakedAccount[msg.sender] = _pendingUnstakedAccount[msg.sender].sub(amount);
          
              _accUnstaked[layer2][msg.sender] = _accUnstaked[layer2][msg.sender].add(amount);
              _accUnstakedLayer2[layer2] = _accUnstakedLayer2[layer2].add(amount);
              _accUnstakedAccount[msg.sender] = _accUnstakedAccount[msg.sender].add(amount);
          
              if (receiveTON) {
                require(_wton.swapToTONAndTransfer(msg.sender, amount));
              } else {
                _wton.safeTransfer(msg.sender, amount);
              }
          
              emit WithdrawalProcessed(layer2, msg.sender, amount);
              return true;
            }
          
            function requestWithdrawalAll(address layer2) external onlyLayer2(layer2) returns (bool) {
              uint256 amount = _seigManager.stakeOf(layer2, msg.sender);
          
              return _requestWithdrawal(layer2, amount);
            }
          
            function processRequests(address layer2, uint256 n, bool receiveTON) external returns (bool) {
              for (uint256 i = 0; i < n; i++) {
                require(_processRequest(layer2, receiveTON));
              }
              return true;
            }
          
            function numRequests(address layer2, address account) external view returns (uint256) {
              return _withdrawalRequests[layer2][account].length;
            }
          
            function numPendingRequests(address layer2, address account) external view returns (uint256) {
              uint256 numRequests = _withdrawalRequests[layer2][account].length;
              uint256 index = _withdrawalRequestIndex[layer2][account];
          
              if (numRequests == 0) return 0;
          
              return numRequests - index;
            }
          
            function _isOperator(address layer2, address operator) internal view returns (bool) {
              return operator == Layer2I(layer2).operator();
            }
          
          
            ////////////////////
            // Storage getters
            ////////////////////
          
            // solium-disable
            function wton() external view returns (address) { return address(_wton); }
            function registry() external view returns (address) { return address(_registry); }
            function seigManager() external view returns (address) { return address(_seigManager); }
          
            function accStaked(address layer2, address account) external view returns (uint256 wtonAmount) { return _accStaked[layer2][account]; }
            function accStakedLayer2(address layer2) external view returns (uint256 wtonAmount) { return _accStakedLayer2[layer2]; }
            function accStakedAccount(address account) external view returns (uint256 wtonAmount) { return _accStakedAccount[account]; }
          
            function pendingUnstaked(address layer2, address account) external view returns (uint256 wtonAmount) { return _pendingUnstaked[layer2][account]; }
            function pendingUnstakedLayer2(address layer2) external view returns (uint256 wtonAmount) { return _pendingUnstakedLayer2[layer2]; }
            function pendingUnstakedAccount(address account) external view returns (uint256 wtonAmount) { return _pendingUnstakedAccount[account]; }
          
            function accUnstaked(address layer2, address account) external view returns (uint256 wtonAmount) { return _accUnstaked[layer2][account]; }
            function accUnstakedLayer2(address layer2) external view returns (uint256 wtonAmount) { return _accUnstakedLayer2[layer2]; }
            function accUnstakedAccount(address account) external view returns (uint256 wtonAmount) { return _accUnstakedAccount[account]; }
          
            function withdrawalRequestIndex(address layer2, address account) external view returns (uint256 index) { return _withdrawalRequestIndex[layer2][account]; }
            function withdrawalRequest(address layer2, address account, uint256 index) external view returns (uint128 withdrawableBlockNumber, uint128 amount, bool processed ) {
              withdrawableBlockNumber = _withdrawalRequests[layer2][account][index].withdrawableBlockNumber;
              amount = _withdrawalRequests[layer2][account][index].amount;
              processed = _withdrawalRequests[layer2][account][index].processed;
            }
          
            // solium-enable
          }

          File 4 of 8: AutoRefactorCoinage
          // based on ERC20 implementation of openzeppelin-solidity: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/7552af95e4ec6fccd64a95b206f59a1b4ff91517/contracts/token/ERC20/ERC20.sol
          pragma solidity ^0.5.12;
          import { AutoRefactorCoinageI } from "AutoRefactorCoinageI.sol";
          import { SafeMath } from "openzeppelin-solidity/SafeMath.sol";
          import { Context } from "openzeppelin-solidity/Context.sol";
          import { Ownable } from "openzeppelin-solidity/Ownable.sol";
          import { IERC20 } from "openzeppelin-solidity/IERC20.sol";
          import { ERC20Detailed } from "openzeppelin-solidity/ERC20Detailed.sol";
          import { ERC20Mintable } from "openzeppelin-solidity/ERC20Mintable.sol";
          import { ERC20Burnable } from "openzeppelin-solidity/ERC20Burnable.sol";
          import { DSMath } from "DSMath.sol";
          /**
           * @dev Implementation of coin age token based on ERC20 of openzeppelin-solidity
           *
           * AutoRefactorCoinage stores `_totalSupply` and `_balances` as RAY BASED value,
           * `_allowances` as RAY FACTORED value.
           *
           * This takes public function (including _approve) parameters as RAY FACTORED value
           * and internal function (including approve) parameters as RAY BASED value, and emits event in RAY FACTORED value.
           *
           * `RAY BASED` = `RAY FACTORED`  / factor
           *
           *  factor increases exponentially for each block mined.
           */
          contract AutoRefactorCoinage is Context, IERC20, DSMath, Ownable, ERC20Detailed, ERC20Mintable, ERC20Burnable {
            using SafeMath for uint256;
            struct Balance {
              uint256 balance;
              uint256 refactoredCount;
              uint256 remain;
            }
            uint256 public REFACTOR_BOUNDARY = 10 ** 28;
            uint256 public REFACTOR_DIVIDER = 2;
            uint256 public refactorCount;
            mapping (address => Balance) public balances;
            Balance public _totalSupply;
            uint256 public _factor;
            bool internal _transfersEnabled;
            event FactorSet(uint256 previous, uint256 current, uint256 shiftCount);
            constructor (
              string memory name,
              string memory symbol,
              uint256 factor
            )
              public
              ERC20Detailed(name, symbol, 27)
            {
              _factor = factor;
              //_factorIncrement = factorIncrement;
              //_lastBlock = block.number;
              //_transfersEnabled = transfersEnabled;
            }
            function factor() public view returns (uint256) {
              uint256 result = _factor;
              for (uint256 i = 0; i < refactorCount; i++) {
                result = result.mul(REFACTOR_DIVIDER);
              }
              return result;
            }
            /**
              * @dev See {IERC20-totalSupply}.
              */
            function totalSupply() public view returns (uint256) {
              return _applyFactor(_totalSupply.balance, _totalSupply.refactoredCount).add(_totalSupply.remain);
            }
            /**
              * @dev See {IERC20-balanceOf}.
              */
            function balanceOf(address account) public view returns (uint256) {
              Balance storage b = balances[account];
              return _applyFactor(b.balance, b.refactoredCount).add(b.remain);
            }
            /** @dev Creates `amount` tokens and assigns them to `account`, increasing
              * the total supply.
              *
              * Emits a {Transfer} event with `from` set to the zero address.
              *
              * Requirements
              *
              * - `to` cannot be the zero address.
              */
            function _mint(address account, uint256 amount) internal {
              require(account != address(0), "AutoRefactorCoinage: mint to the zero address");
              Balance storage b = balances[account];
              uint256 currentBalance = balanceOf(account);
              uint256 newBalance = currentBalance.add(amount);
              uint256 rbAmount = _toRAYBased(newBalance);
              b.balance = rbAmount;
              b.refactoredCount = refactorCount;
              addTotalSupply(amount);
              emit Transfer(address(0), account, _toRAYFactored(rbAmount));
            }
              /**
              * @dev Destroys `amount` tokens from `account`, reducing the
              * total supply.
              *
              * Emits a {Transfer} event with `to` set to the zero address.
              *
              * Requirements
              *
              * - `account` cannot be the zero address.
              * - `account` must have at least `amount` tokens.
              */
            function _burn(address account, uint256 amount) internal {
              require(account != address(0), "AutoRefactorCoinage: burn from the zero address");
              Balance storage b = balances[account];
              uint256 currentBalance = balanceOf(account);
              uint256 newBalance = currentBalance.sub(amount);
              uint256 rbAmount = _toRAYBased(newBalance);
              b.balance = rbAmount;
              b.refactoredCount = refactorCount;
              subTotalSupply(amount);
              emit Transfer(account, address(0), _toRAYFactored(rbAmount));
            }
            function _burnFrom(address account, uint256 amount) internal {
              _burn(account, amount);
            }
            // helpers
            /**
             * @param v the value to be factored
             */
            function _applyFactor(uint256 v, uint256 refactoredCount) internal view returns (uint256) {
              if (v == 0) {
                return 0;
              }
              v = rmul2(v, _factor);
              for (uint256 i = refactoredCount; i < refactorCount; i++) {
                v = v.mul(REFACTOR_DIVIDER);
              }
              return v;
            }
            /**
             * @dev Calculate RAY BASED from RAY FACTORED
             */
            function _toRAYBased(uint256 rf) internal view returns (uint256 rb) {
              return rdiv2(rf, _factor);
            }
            /**
             * @dev Calculate RAY FACTORED from RAY BASED
             */
            function _toRAYFactored(uint256 rb) internal view returns (uint256 rf) {
              return rmul2(rb, _factor);
            }
            // new
            function setFactor(uint256 factor) external onlyOwner returns (bool) {
              uint256 previous = _factor;
              uint256 count = 0;
              uint256 f = factor;
              for (; f >= REFACTOR_BOUNDARY; f = f.div(REFACTOR_DIVIDER)) {
                count = count.add(1);
              }
              refactorCount = count;
              _factor = f;
              emit FactorSet(previous, f, count);
            }
            function addTotalSupply(uint256 amount) internal {
              uint256 currentSupply = _applyFactor(_totalSupply.balance, _totalSupply.refactoredCount);
              uint256 newSupply = currentSupply.add(amount);
              uint256 rbAmount = _toRAYBased(newSupply);
              _totalSupply.balance = rbAmount;
              _totalSupply.refactoredCount = refactorCount;
            }
            function subTotalSupply(uint256 amount) internal {
              uint256 currentSupply = _applyFactor(_totalSupply.balance, _totalSupply.refactoredCount);
              uint256 newSupply = currentSupply.sub(amount);
              uint256 rbAmount = _toRAYBased(newSupply);
              _totalSupply.balance = rbAmount;
              _totalSupply.refactoredCount = refactorCount;
            }
            // unsupported functions
            function transfer(address recipient, uint256 amount) public returns (bool) {
              revert();
            }
            function allowance(address owner, address spender) public view returns (uint256) {
              return 0;
            }
            function approve(address spender, uint256 amount) public returns (bool) {
              revert();
            }
            function transferFrom(address sender, address recipient, uint256 amount) public returns (bool) {
              revert();
            }
          }
          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;
              }
          }
          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);
              /**
               * @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);
          }
          // https://github.com/dapphub/ds-math/blob/de45767/src/math.sol
          /// math.sol -- mixin for inline numerical wizardry
          // This program is free software: you can redistribute it and/or modify
          // it under the terms of the GNU General Public License as published by
          // the Free Software Foundation, either version 3 of the License, or
          // (at your option) any later version.
          // This program is distributed in the hope that it will be useful,
          // but WITHOUT ANY WARRANTY; without even the implied warranty of
          // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
          // GNU General Public License for more details.
          // You should have received a copy of the GNU General Public License
          // along with this program.  If not, see <http://www.gnu.org/licenses/>.
          pragma solidity >0.4.13;
          contract DSMath {
            function add(uint x, uint y) internal pure returns (uint z) {
              require((z = x + y) >= x, "ds-math-add-overflow");
            }
            function sub(uint x, uint y) internal pure returns (uint z) {
              require((z = x - y) <= x, "ds-math-sub-underflow");
            }
            function mul(uint x, uint y) internal pure returns (uint z) {
              require(y == 0 || (z = x * y) / y == x, "ds-math-mul-overflow");
            }
            function min(uint x, uint y) internal pure returns (uint z) {
              return x <= y ? x : y;
            }
            function max(uint x, uint y) internal pure returns (uint z) {
              return x >= y ? x : y;
            }
            function imin(int x, int y) internal pure returns (int z) {
              return x <= y ? x : y;
            }
            function imax(int x, int y) internal pure returns (int z) {
              return x >= y ? x : y;
            }
            uint constant WAD = 10 ** 18;
            uint constant RAY = 10 ** 27;
            function wmul(uint x, uint y) internal pure returns (uint z) {
              z = add(mul(x, y), WAD / 2) / WAD;
            }
            function rmul(uint x, uint y) internal pure returns (uint z) {
              z = add(mul(x, y), RAY / 2) / RAY;
            }
            function wdiv(uint x, uint y) internal pure returns (uint z) {
              z = add(mul(x, WAD), y / 2) / y;
            }
            function rdiv(uint x, uint y) internal pure returns (uint z) {
              z = add(mul(x, RAY), y / 2) / y;
            }
            function wmul2(uint x, uint y) internal pure returns (uint z) {
              z = mul(x, y) / WAD;
            }
            function rmul2(uint x, uint y) internal pure returns (uint z) {
              z = mul(x, y) / RAY;
            }
            function wdiv2(uint x, uint y) internal pure returns (uint z) {
              z = mul(x, WAD) / y;
            }
            function rdiv2(uint x, uint y) internal pure returns (uint z) {
              z = mul(x, RAY) / y;
            }
            // This famous algorithm is called "exponentiation by squaring"
            // and calculates x^n with x as fixed-point and n as regular unsigned.
            //
            // It's O(log n), instead of O(n) for naive repeated multiplication.
            //
            // These facts are why it works:
            //
            //  If n is even, then x^n = (x^2)^(n/2).
            //  If n is odd,  then x^n = x * x^(n-1),
            //   and applying the equation for even x gives
            //  x^n = x * (x^2)^((n-1) / 2).
            //
            //  Also, EVM division is flooring and
            //  floor[(n-1) / 2] = floor[n / 2].
            //
            function wpow(uint x, uint n) internal pure returns (uint z) {
              z = n % 2 != 0 ? x : WAD;
              for (n /= 2; n != 0; n /= 2) {
                x = wmul(x, x);
                if (n % 2 != 0) {
                  z = wmul(z, x);
                }
              }
            }
            function rpow(uint x, uint n) internal pure returns (uint z) {
              z = n % 2 != 0 ? x : RAY;
              for (n /= 2; n != 0; n /= 2) {
                x = rmul(x, x);
                if (n % 2 != 0) {
                  z = rmul(z, x);
                }
              }
            }
          }
          pragma solidity ^0.5.0;
          import "openzeppelin-solidity/Context.sol";
          /**
           * @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 {
                  address msgSender = _msgSender();
                  _owner = msgSender;
                  emit OwnershipTransferred(address(0), msgSender);
              }
              /**
               * @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;
              }
          }
          pragma solidity ^0.5.0;
          import "openzeppelin-solidity/ERC20.sol";
          import "openzeppelin-solidity/MinterRole.sol";
          /**
           * @dev Extension of {ERC20} that adds a set of accounts with the {MinterRole},
           * which have permission to mint (create) new tokens as they see fit.
           *
           * At construction, the deployer of the contract is the only minter.
           */
          contract ERC20Mintable is ERC20, MinterRole {
              /**
               * @dev See {ERC20-_mint}.
               *
               * Requirements:
               *
               * - the caller must have the {MinterRole}.
               */
              function mint(address account, uint256 amount) public onlyMinter returns (bool) {
                  _mint(account, amount);
                  return true;
              }
          }
          pragma solidity ^0.5.0;
          import "openzeppelin-solidity/IERC20.sol";
          /**
           * @dev Optional functions from the ERC20 standard.
           */
          contract ERC20Detailed is IERC20 {
              string private _name;
              string private _symbol;
              uint8 private _decimals;
              /**
               * @dev Sets the values for `name`, `symbol`, and `decimals`. All three of
               * these values are immutable: they can only be set once during
               * construction.
               */
              constructor (string memory name, string memory symbol, uint8 decimals) public {
                  _name = name;
                  _symbol = symbol;
                  _decimals = decimals;
              }
              /**
               * @dev Returns the name of the token.
               */
              function name() public view returns (string memory) {
                  return _name;
              }
              /**
               * @dev Returns the symbol of the token, usually a shorter version of the
               * name.
               */
              function symbol() public view returns (string memory) {
                  return _symbol;
              }
              /**
               * @dev Returns the number of decimals used to get its user representation.
               * For example, if `decimals` equals `2`, a balance of `505` tokens should
               * be displayed to a user as `5,05` (`505 / 10 ** 2`).
               *
               * Tokens usually opt for a value of 18, imitating the relationship between
               * Ether and Wei.
               *
               * NOTE: This information is only used for _display_ purposes: it in
               * no way affects any of the arithmetic of the contract, including
               * {IERC20-balanceOf} and {IERC20-transfer}.
               */
              function decimals() public view returns (uint8) {
                  return _decimals;
              }
          }
          pragma solidity ^0.5.0;
          import "openzeppelin-solidity/Context.sol";
          import "openzeppelin-solidity/ERC20.sol";
          /**
           * @dev Extension of {ERC20} that allows token holders to destroy both their own
           * tokens and those that they have an allowance for, in a way that can be
           * recognized off-chain (via event analysis).
           */
          contract ERC20Burnable is Context, ERC20 {
              /**
               * @dev Destroys `amount` tokens from the caller.
               *
               * See {ERC20-_burn}.
               */
              function burn(uint256 amount) public {
                  _burn(_msgSender(), amount);
              }
              /**
               * @dev See {ERC20-_burnFrom}.
               */
              function burnFrom(address account, uint256 amount) public {
                  _burnFrom(account, amount);
              }
          }
          pragma solidity ^0.5.0;
          import "openzeppelin-solidity/Context.sol";
          import "openzeppelin-solidity/IERC20.sol";
          import "openzeppelin-solidity/SafeMath.sol";
          /**
           * @dev Implementation of the {IERC20} interface.
           *
           * This implementation is agnostic to the way tokens are created. This means
           * that a supply mechanism has to be added in a derived contract using {_mint}.
           * For a generic mechanism see {ERC20Mintable}.
           *
           * TIP: For a detailed writeup see our guide
           * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How
           * to implement supply mechanisms].
           *
           * We have followed general OpenZeppelin guidelines: functions revert instead
           * of returning `false` on failure. This behavior is nonetheless conventional
           * and does not conflict with the expectations of ERC20 applications.
           *
           * Additionally, an {Approval} event is emitted on calls to {transferFrom}.
           * This allows applications to reconstruct the allowance for all accounts just
           * by listening to said events. Other implementations of the EIP may not emit
           * these events, as it isn't required by the specification.
           *
           * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}
           * functions have been added to mitigate the well-known issues around setting
           * allowances. See {IERC20-approve}.
           */
          contract ERC20 is Context, IERC20 {
              using SafeMath for uint256;
              mapping (address => uint256) private _balances;
              mapping (address => mapping (address => uint256)) private _allowances;
              uint256 private _totalSupply;
              /**
               * @dev See {IERC20-totalSupply}.
               */
              function totalSupply() public view returns (uint256) {
                  return _totalSupply;
              }
              /**
               * @dev See {IERC20-balanceOf}.
               */
              function balanceOf(address account) public view returns (uint256) {
                  return _balances[account];
              }
              /**
               * @dev See {IERC20-transfer}.
               *
               * Requirements:
               *
               * - `recipient` cannot be the zero address.
               * - the caller must have a balance of at least `amount`.
               */
              function transfer(address recipient, uint256 amount) public returns (bool) {
                  _transfer(_msgSender(), recipient, amount);
                  return true;
              }
              /**
               * @dev See {IERC20-allowance}.
               */
              function allowance(address owner, address spender) public view returns (uint256) {
                  return _allowances[owner][spender];
              }
              /**
               * @dev See {IERC20-approve}.
               *
               * Requirements:
               *
               * - `spender` cannot be the zero address.
               */
              function approve(address spender, uint256 amount) public returns (bool) {
                  _approve(_msgSender(), spender, amount);
                  return true;
              }
              /**
               * @dev See {IERC20-transferFrom}.
               *
               * Emits an {Approval} event indicating the updated allowance. This is not
               * required by the EIP. See the note at the beginning of {ERC20};
               *
               * Requirements:
               * - `sender` and `recipient` cannot be the zero address.
               * - `sender` must have a balance of at least `amount`.
               * - the caller must have allowance for `sender`'s tokens of at least
               * `amount`.
               */
              function transferFrom(address sender, address recipient, uint256 amount) public returns (bool) {
                  _transfer(sender, recipient, amount);
                  _approve(sender, _msgSender(), _allowances[sender][_msgSender()].sub(amount, "ERC20: transfer amount exceeds allowance"));
                  return true;
              }
              /**
               * @dev Atomically increases the allowance granted to `spender` by the caller.
               *
               * This is an alternative to {approve} that can be used as a mitigation for
               * problems described in {IERC20-approve}.
               *
               * Emits an {Approval} event indicating the updated allowance.
               *
               * Requirements:
               *
               * - `spender` cannot be the zero address.
               */
              function increaseAllowance(address spender, uint256 addedValue) public returns (bool) {
                  _approve(_msgSender(), spender, _allowances[_msgSender()][spender].add(addedValue));
                  return true;
              }
              /**
               * @dev Atomically decreases the allowance granted to `spender` by the caller.
               *
               * This is an alternative to {approve} that can be used as a mitigation for
               * problems described in {IERC20-approve}.
               *
               * Emits an {Approval} event indicating the updated allowance.
               *
               * Requirements:
               *
               * - `spender` cannot be the zero address.
               * - `spender` must have allowance for the caller of at least
               * `subtractedValue`.
               */
              function decreaseAllowance(address spender, uint256 subtractedValue) public returns (bool) {
                  _approve(_msgSender(), spender, _allowances[_msgSender()][spender].sub(subtractedValue, "ERC20: decreased allowance below zero"));
                  return true;
              }
              /**
               * @dev Moves tokens `amount` from `sender` to `recipient`.
               *
               * This is internal function is equivalent to {transfer}, and can be used to
               * e.g. implement automatic token fees, slashing mechanisms, etc.
               *
               * Emits a {Transfer} event.
               *
               * Requirements:
               *
               * - `sender` cannot be the zero address.
               * - `recipient` cannot be the zero address.
               * - `sender` must have a balance of at least `amount`.
               */
              function _transfer(address sender, address recipient, uint256 amount) internal {
                  require(sender != address(0), "ERC20: transfer from the zero address");
                  require(recipient != address(0), "ERC20: transfer to the zero address");
                  _balances[sender] = _balances[sender].sub(amount, "ERC20: transfer amount exceeds balance");
                  _balances[recipient] = _balances[recipient].add(amount);
                  emit Transfer(sender, recipient, amount);
              }
              /** @dev Creates `amount` tokens and assigns them to `account`, increasing
               * the total supply.
               *
               * Emits a {Transfer} event with `from` set to the zero address.
               *
               * Requirements
               *
               * - `to` cannot be the zero address.
               */
              function _mint(address account, uint256 amount) internal {
                  require(account != address(0), "ERC20: mint to the zero address");
                  _totalSupply = _totalSupply.add(amount);
                  _balances[account] = _balances[account].add(amount);
                  emit Transfer(address(0), account, amount);
              }
              /**
               * @dev Destroys `amount` tokens from `account`, reducing the
               * total supply.
               *
               * Emits a {Transfer} event with `to` set to the zero address.
               *
               * Requirements
               *
               * - `account` cannot be the zero address.
               * - `account` must have at least `amount` tokens.
               */
              function _burn(address account, uint256 amount) internal {
                  require(account != address(0), "ERC20: burn from the zero address");
                  _balances[account] = _balances[account].sub(amount, "ERC20: burn amount exceeds balance");
                  _totalSupply = _totalSupply.sub(amount);
                  emit Transfer(account, address(0), amount);
              }
              /**
               * @dev Sets `amount` as the allowance of `spender` over the `owner`s tokens.
               *
               * This is internal function is equivalent to `approve`, and can be used to
               * e.g. set automatic allowances for certain subsystems, etc.
               *
               * Emits an {Approval} event.
               *
               * Requirements:
               *
               * - `owner` cannot be the zero address.
               * - `spender` cannot be the zero address.
               */
              function _approve(address owner, address spender, uint256 amount) internal {
                  require(owner != address(0), "ERC20: approve from the zero address");
                  require(spender != address(0), "ERC20: approve to the zero address");
                  _allowances[owner][spender] = amount;
                  emit Approval(owner, spender, amount);
              }
              /**
               * @dev Destroys `amount` tokens from `account`.`amount` is then deducted
               * from the caller's allowance.
               *
               * See {_burn} and {_approve}.
               */
              function _burnFrom(address account, uint256 amount) internal {
                  _burn(account, amount);
                  _approve(account, _msgSender(), _allowances[account][_msgSender()].sub(amount, "ERC20: burn amount exceeds allowance"));
              }
          }
          pragma solidity ^0.5.0;
          import "openzeppelin-solidity/Context.sol";
          import "openzeppelin-solidity/Roles.sol";
          contract MinterRole is Context {
              using Roles for Roles.Role;
              event MinterAdded(address indexed account);
              event MinterRemoved(address indexed account);
              Roles.Role private _minters;
              constructor () internal {
                  _addMinter(_msgSender());
              }
              modifier onlyMinter() {
                  require(isMinter(_msgSender()), "MinterRole: caller does not have the Minter role");
                  _;
              }
              function isMinter(address account) public view returns (bool) {
                  return _minters.has(account);
              }
              function addMinter(address account) public onlyMinter {
                  _addMinter(account);
              }
              function renounceMinter() public {
                  _removeMinter(_msgSender());
              }
              function _addMinter(address account) internal {
                  _minters.add(account);
                  emit MinterAdded(account);
              }
              function _removeMinter(address account) internal {
                  _minters.remove(account);
                  emit MinterRemoved(account);
              }
          }
          pragma solidity ^0.5.0;
          /**
           * @title Roles
           * @dev Library for managing addresses assigned to a Role.
           */
          library Roles {
              struct Role {
                  mapping (address => bool) bearer;
              }
              /**
               * @dev Give an account access to this role.
               */
              function add(Role storage role, address account) internal {
                  require(!has(role, account), "Roles: account already has role");
                  role.bearer[account] = true;
              }
              /**
               * @dev Remove an account's access to this role.
               */
              function remove(Role storage role, address account) internal {
                  require(has(role, account), "Roles: account does not have role");
                  role.bearer[account] = false;
              }
              /**
               * @dev Check if an account has this role.
               * @return bool
               */
              function has(Role storage role, address account) internal view returns (bool) {
                  require(account != address(0), "Roles: account is the zero address");
                  return role.bearer[account];
              }
          }
          pragma solidity ^0.5.12;
          interface AutoRefactorCoinageI {
            function factor() external view returns (uint256);
            function setFactor(uint256 factor) external returns (bool);
            function burn(uint256 amount) external;
            function burnFrom(address account, uint256 amount) external;
            function mint(address account, uint256 amount) external returns (bool);
            function totalSupply() external view returns (uint256);
            function balanceOf(address account) external view returns (uint256);
            function addMinter(address account) external;
            function renounceMinter() external;
            function transferOwnership(address newOwner) external;
          }
          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 5 of 8: AutoRefactorCoinage
          // based on ERC20 implementation of openzeppelin-solidity: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/7552af95e4ec6fccd64a95b206f59a1b4ff91517/contracts/token/ERC20/ERC20.sol
          pragma solidity ^0.5.12;
          import { AutoRefactorCoinageI } from "AutoRefactorCoinageI.sol";
          import { SafeMath } from "openzeppelin-solidity/SafeMath.sol";
          import { Context } from "openzeppelin-solidity/Context.sol";
          import { Ownable } from "openzeppelin-solidity/Ownable.sol";
          import { IERC20 } from "openzeppelin-solidity/IERC20.sol";
          import { ERC20Detailed } from "openzeppelin-solidity/ERC20Detailed.sol";
          import { ERC20Mintable } from "openzeppelin-solidity/ERC20Mintable.sol";
          import { ERC20Burnable } from "openzeppelin-solidity/ERC20Burnable.sol";
          import { DSMath } from "DSMath.sol";
          /**
           * @dev Implementation of coin age token based on ERC20 of openzeppelin-solidity
           *
           * AutoRefactorCoinage stores `_totalSupply` and `_balances` as RAY BASED value,
           * `_allowances` as RAY FACTORED value.
           *
           * This takes public function (including _approve) parameters as RAY FACTORED value
           * and internal function (including approve) parameters as RAY BASED value, and emits event in RAY FACTORED value.
           *
           * `RAY BASED` = `RAY FACTORED`  / factor
           *
           *  factor increases exponentially for each block mined.
           */
          contract AutoRefactorCoinage is Context, IERC20, DSMath, Ownable, ERC20Detailed, ERC20Mintable, ERC20Burnable {
            using SafeMath for uint256;
            struct Balance {
              uint256 balance;
              uint256 refactoredCount;
              uint256 remain;
            }
            uint256 public REFACTOR_BOUNDARY = 10 ** 28;
            uint256 public REFACTOR_DIVIDER = 2;
            uint256 public refactorCount;
            mapping (address => Balance) public balances;
            Balance public _totalSupply;
            uint256 public _factor;
            bool internal _transfersEnabled;
            event FactorSet(uint256 previous, uint256 current, uint256 shiftCount);
            constructor (
              string memory name,
              string memory symbol,
              uint256 factor
            )
              public
              ERC20Detailed(name, symbol, 27)
            {
              _factor = factor;
              //_factorIncrement = factorIncrement;
              //_lastBlock = block.number;
              //_transfersEnabled = transfersEnabled;
            }
            function factor() public view returns (uint256) {
              uint256 result = _factor;
              for (uint256 i = 0; i < refactorCount; i++) {
                result = result.mul(REFACTOR_DIVIDER);
              }
              return result;
            }
            /**
              * @dev See {IERC20-totalSupply}.
              */
            function totalSupply() public view returns (uint256) {
              return _applyFactor(_totalSupply.balance, _totalSupply.refactoredCount).add(_totalSupply.remain);
            }
            /**
              * @dev See {IERC20-balanceOf}.
              */
            function balanceOf(address account) public view returns (uint256) {
              Balance storage b = balances[account];
              return _applyFactor(b.balance, b.refactoredCount).add(b.remain);
            }
            /** @dev Creates `amount` tokens and assigns them to `account`, increasing
              * the total supply.
              *
              * Emits a {Transfer} event with `from` set to the zero address.
              *
              * Requirements
              *
              * - `to` cannot be the zero address.
              */
            function _mint(address account, uint256 amount) internal {
              require(account != address(0), "AutoRefactorCoinage: mint to the zero address");
              Balance storage b = balances[account];
              uint256 currentBalance = balanceOf(account);
              uint256 newBalance = currentBalance.add(amount);
              uint256 rbAmount = _toRAYBased(newBalance);
              b.balance = rbAmount;
              b.refactoredCount = refactorCount;
              addTotalSupply(amount);
              emit Transfer(address(0), account, _toRAYFactored(rbAmount));
            }
              /**
              * @dev Destroys `amount` tokens from `account`, reducing the
              * total supply.
              *
              * Emits a {Transfer} event with `to` set to the zero address.
              *
              * Requirements
              *
              * - `account` cannot be the zero address.
              * - `account` must have at least `amount` tokens.
              */
            function _burn(address account, uint256 amount) internal {
              require(account != address(0), "AutoRefactorCoinage: burn from the zero address");
              Balance storage b = balances[account];
              uint256 currentBalance = balanceOf(account);
              uint256 newBalance = currentBalance.sub(amount);
              uint256 rbAmount = _toRAYBased(newBalance);
              b.balance = rbAmount;
              b.refactoredCount = refactorCount;
              subTotalSupply(amount);
              emit Transfer(account, address(0), _toRAYFactored(rbAmount));
            }
            function _burnFrom(address account, uint256 amount) internal {
              _burn(account, amount);
            }
            // helpers
            /**
             * @param v the value to be factored
             */
            function _applyFactor(uint256 v, uint256 refactoredCount) internal view returns (uint256) {
              if (v == 0) {
                return 0;
              }
              v = rmul2(v, _factor);
              for (uint256 i = refactoredCount; i < refactorCount; i++) {
                v = v.mul(REFACTOR_DIVIDER);
              }
              return v;
            }
            /**
             * @dev Calculate RAY BASED from RAY FACTORED
             */
            function _toRAYBased(uint256 rf) internal view returns (uint256 rb) {
              return rdiv2(rf, _factor);
            }
            /**
             * @dev Calculate RAY FACTORED from RAY BASED
             */
            function _toRAYFactored(uint256 rb) internal view returns (uint256 rf) {
              return rmul2(rb, _factor);
            }
            // new
            function setFactor(uint256 factor) external onlyOwner returns (bool) {
              uint256 previous = _factor;
              uint256 count = 0;
              uint256 f = factor;
              for (; f >= REFACTOR_BOUNDARY; f = f.div(REFACTOR_DIVIDER)) {
                count = count.add(1);
              }
              refactorCount = count;
              _factor = f;
              emit FactorSet(previous, f, count);
            }
            function addTotalSupply(uint256 amount) internal {
              uint256 currentSupply = _applyFactor(_totalSupply.balance, _totalSupply.refactoredCount);
              uint256 newSupply = currentSupply.add(amount);
              uint256 rbAmount = _toRAYBased(newSupply);
              _totalSupply.balance = rbAmount;
              _totalSupply.refactoredCount = refactorCount;
            }
            function subTotalSupply(uint256 amount) internal {
              uint256 currentSupply = _applyFactor(_totalSupply.balance, _totalSupply.refactoredCount);
              uint256 newSupply = currentSupply.sub(amount);
              uint256 rbAmount = _toRAYBased(newSupply);
              _totalSupply.balance = rbAmount;
              _totalSupply.refactoredCount = refactorCount;
            }
            // unsupported functions
            function transfer(address recipient, uint256 amount) public returns (bool) {
              revert();
            }
            function allowance(address owner, address spender) public view returns (uint256) {
              return 0;
            }
            function approve(address spender, uint256 amount) public returns (bool) {
              revert();
            }
            function transferFrom(address sender, address recipient, uint256 amount) public returns (bool) {
              revert();
            }
          }
          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;
              }
          }
          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);
              /**
               * @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);
          }
          // https://github.com/dapphub/ds-math/blob/de45767/src/math.sol
          /// math.sol -- mixin for inline numerical wizardry
          // This program is free software: you can redistribute it and/or modify
          // it under the terms of the GNU General Public License as published by
          // the Free Software Foundation, either version 3 of the License, or
          // (at your option) any later version.
          // This program is distributed in the hope that it will be useful,
          // but WITHOUT ANY WARRANTY; without even the implied warranty of
          // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
          // GNU General Public License for more details.
          // You should have received a copy of the GNU General Public License
          // along with this program.  If not, see <http://www.gnu.org/licenses/>.
          pragma solidity >0.4.13;
          contract DSMath {
            function add(uint x, uint y) internal pure returns (uint z) {
              require((z = x + y) >= x, "ds-math-add-overflow");
            }
            function sub(uint x, uint y) internal pure returns (uint z) {
              require((z = x - y) <= x, "ds-math-sub-underflow");
            }
            function mul(uint x, uint y) internal pure returns (uint z) {
              require(y == 0 || (z = x * y) / y == x, "ds-math-mul-overflow");
            }
            function min(uint x, uint y) internal pure returns (uint z) {
              return x <= y ? x : y;
            }
            function max(uint x, uint y) internal pure returns (uint z) {
              return x >= y ? x : y;
            }
            function imin(int x, int y) internal pure returns (int z) {
              return x <= y ? x : y;
            }
            function imax(int x, int y) internal pure returns (int z) {
              return x >= y ? x : y;
            }
            uint constant WAD = 10 ** 18;
            uint constant RAY = 10 ** 27;
            function wmul(uint x, uint y) internal pure returns (uint z) {
              z = add(mul(x, y), WAD / 2) / WAD;
            }
            function rmul(uint x, uint y) internal pure returns (uint z) {
              z = add(mul(x, y), RAY / 2) / RAY;
            }
            function wdiv(uint x, uint y) internal pure returns (uint z) {
              z = add(mul(x, WAD), y / 2) / y;
            }
            function rdiv(uint x, uint y) internal pure returns (uint z) {
              z = add(mul(x, RAY), y / 2) / y;
            }
            function wmul2(uint x, uint y) internal pure returns (uint z) {
              z = mul(x, y) / WAD;
            }
            function rmul2(uint x, uint y) internal pure returns (uint z) {
              z = mul(x, y) / RAY;
            }
            function wdiv2(uint x, uint y) internal pure returns (uint z) {
              z = mul(x, WAD) / y;
            }
            function rdiv2(uint x, uint y) internal pure returns (uint z) {
              z = mul(x, RAY) / y;
            }
            // This famous algorithm is called "exponentiation by squaring"
            // and calculates x^n with x as fixed-point and n as regular unsigned.
            //
            // It's O(log n), instead of O(n) for naive repeated multiplication.
            //
            // These facts are why it works:
            //
            //  If n is even, then x^n = (x^2)^(n/2).
            //  If n is odd,  then x^n = x * x^(n-1),
            //   and applying the equation for even x gives
            //  x^n = x * (x^2)^((n-1) / 2).
            //
            //  Also, EVM division is flooring and
            //  floor[(n-1) / 2] = floor[n / 2].
            //
            function wpow(uint x, uint n) internal pure returns (uint z) {
              z = n % 2 != 0 ? x : WAD;
              for (n /= 2; n != 0; n /= 2) {
                x = wmul(x, x);
                if (n % 2 != 0) {
                  z = wmul(z, x);
                }
              }
            }
            function rpow(uint x, uint n) internal pure returns (uint z) {
              z = n % 2 != 0 ? x : RAY;
              for (n /= 2; n != 0; n /= 2) {
                x = rmul(x, x);
                if (n % 2 != 0) {
                  z = rmul(z, x);
                }
              }
            }
          }
          pragma solidity ^0.5.0;
          import "openzeppelin-solidity/Context.sol";
          /**
           * @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 {
                  address msgSender = _msgSender();
                  _owner = msgSender;
                  emit OwnershipTransferred(address(0), msgSender);
              }
              /**
               * @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;
              }
          }
          pragma solidity ^0.5.0;
          import "openzeppelin-solidity/ERC20.sol";
          import "openzeppelin-solidity/MinterRole.sol";
          /**
           * @dev Extension of {ERC20} that adds a set of accounts with the {MinterRole},
           * which have permission to mint (create) new tokens as they see fit.
           *
           * At construction, the deployer of the contract is the only minter.
           */
          contract ERC20Mintable is ERC20, MinterRole {
              /**
               * @dev See {ERC20-_mint}.
               *
               * Requirements:
               *
               * - the caller must have the {MinterRole}.
               */
              function mint(address account, uint256 amount) public onlyMinter returns (bool) {
                  _mint(account, amount);
                  return true;
              }
          }
          pragma solidity ^0.5.0;
          import "openzeppelin-solidity/IERC20.sol";
          /**
           * @dev Optional functions from the ERC20 standard.
           */
          contract ERC20Detailed is IERC20 {
              string private _name;
              string private _symbol;
              uint8 private _decimals;
              /**
               * @dev Sets the values for `name`, `symbol`, and `decimals`. All three of
               * these values are immutable: they can only be set once during
               * construction.
               */
              constructor (string memory name, string memory symbol, uint8 decimals) public {
                  _name = name;
                  _symbol = symbol;
                  _decimals = decimals;
              }
              /**
               * @dev Returns the name of the token.
               */
              function name() public view returns (string memory) {
                  return _name;
              }
              /**
               * @dev Returns the symbol of the token, usually a shorter version of the
               * name.
               */
              function symbol() public view returns (string memory) {
                  return _symbol;
              }
              /**
               * @dev Returns the number of decimals used to get its user representation.
               * For example, if `decimals` equals `2`, a balance of `505` tokens should
               * be displayed to a user as `5,05` (`505 / 10 ** 2`).
               *
               * Tokens usually opt for a value of 18, imitating the relationship between
               * Ether and Wei.
               *
               * NOTE: This information is only used for _display_ purposes: it in
               * no way affects any of the arithmetic of the contract, including
               * {IERC20-balanceOf} and {IERC20-transfer}.
               */
              function decimals() public view returns (uint8) {
                  return _decimals;
              }
          }
          pragma solidity ^0.5.0;
          import "openzeppelin-solidity/Context.sol";
          import "openzeppelin-solidity/ERC20.sol";
          /**
           * @dev Extension of {ERC20} that allows token holders to destroy both their own
           * tokens and those that they have an allowance for, in a way that can be
           * recognized off-chain (via event analysis).
           */
          contract ERC20Burnable is Context, ERC20 {
              /**
               * @dev Destroys `amount` tokens from the caller.
               *
               * See {ERC20-_burn}.
               */
              function burn(uint256 amount) public {
                  _burn(_msgSender(), amount);
              }
              /**
               * @dev See {ERC20-_burnFrom}.
               */
              function burnFrom(address account, uint256 amount) public {
                  _burnFrom(account, amount);
              }
          }
          pragma solidity ^0.5.0;
          import "openzeppelin-solidity/Context.sol";
          import "openzeppelin-solidity/IERC20.sol";
          import "openzeppelin-solidity/SafeMath.sol";
          /**
           * @dev Implementation of the {IERC20} interface.
           *
           * This implementation is agnostic to the way tokens are created. This means
           * that a supply mechanism has to be added in a derived contract using {_mint}.
           * For a generic mechanism see {ERC20Mintable}.
           *
           * TIP: For a detailed writeup see our guide
           * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How
           * to implement supply mechanisms].
           *
           * We have followed general OpenZeppelin guidelines: functions revert instead
           * of returning `false` on failure. This behavior is nonetheless conventional
           * and does not conflict with the expectations of ERC20 applications.
           *
           * Additionally, an {Approval} event is emitted on calls to {transferFrom}.
           * This allows applications to reconstruct the allowance for all accounts just
           * by listening to said events. Other implementations of the EIP may not emit
           * these events, as it isn't required by the specification.
           *
           * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}
           * functions have been added to mitigate the well-known issues around setting
           * allowances. See {IERC20-approve}.
           */
          contract ERC20 is Context, IERC20 {
              using SafeMath for uint256;
              mapping (address => uint256) private _balances;
              mapping (address => mapping (address => uint256)) private _allowances;
              uint256 private _totalSupply;
              /**
               * @dev See {IERC20-totalSupply}.
               */
              function totalSupply() public view returns (uint256) {
                  return _totalSupply;
              }
              /**
               * @dev See {IERC20-balanceOf}.
               */
              function balanceOf(address account) public view returns (uint256) {
                  return _balances[account];
              }
              /**
               * @dev See {IERC20-transfer}.
               *
               * Requirements:
               *
               * - `recipient` cannot be the zero address.
               * - the caller must have a balance of at least `amount`.
               */
              function transfer(address recipient, uint256 amount) public returns (bool) {
                  _transfer(_msgSender(), recipient, amount);
                  return true;
              }
              /**
               * @dev See {IERC20-allowance}.
               */
              function allowance(address owner, address spender) public view returns (uint256) {
                  return _allowances[owner][spender];
              }
              /**
               * @dev See {IERC20-approve}.
               *
               * Requirements:
               *
               * - `spender` cannot be the zero address.
               */
              function approve(address spender, uint256 amount) public returns (bool) {
                  _approve(_msgSender(), spender, amount);
                  return true;
              }
              /**
               * @dev See {IERC20-transferFrom}.
               *
               * Emits an {Approval} event indicating the updated allowance. This is not
               * required by the EIP. See the note at the beginning of {ERC20};
               *
               * Requirements:
               * - `sender` and `recipient` cannot be the zero address.
               * - `sender` must have a balance of at least `amount`.
               * - the caller must have allowance for `sender`'s tokens of at least
               * `amount`.
               */
              function transferFrom(address sender, address recipient, uint256 amount) public returns (bool) {
                  _transfer(sender, recipient, amount);
                  _approve(sender, _msgSender(), _allowances[sender][_msgSender()].sub(amount, "ERC20: transfer amount exceeds allowance"));
                  return true;
              }
              /**
               * @dev Atomically increases the allowance granted to `spender` by the caller.
               *
               * This is an alternative to {approve} that can be used as a mitigation for
               * problems described in {IERC20-approve}.
               *
               * Emits an {Approval} event indicating the updated allowance.
               *
               * Requirements:
               *
               * - `spender` cannot be the zero address.
               */
              function increaseAllowance(address spender, uint256 addedValue) public returns (bool) {
                  _approve(_msgSender(), spender, _allowances[_msgSender()][spender].add(addedValue));
                  return true;
              }
              /**
               * @dev Atomically decreases the allowance granted to `spender` by the caller.
               *
               * This is an alternative to {approve} that can be used as a mitigation for
               * problems described in {IERC20-approve}.
               *
               * Emits an {Approval} event indicating the updated allowance.
               *
               * Requirements:
               *
               * - `spender` cannot be the zero address.
               * - `spender` must have allowance for the caller of at least
               * `subtractedValue`.
               */
              function decreaseAllowance(address spender, uint256 subtractedValue) public returns (bool) {
                  _approve(_msgSender(), spender, _allowances[_msgSender()][spender].sub(subtractedValue, "ERC20: decreased allowance below zero"));
                  return true;
              }
              /**
               * @dev Moves tokens `amount` from `sender` to `recipient`.
               *
               * This is internal function is equivalent to {transfer}, and can be used to
               * e.g. implement automatic token fees, slashing mechanisms, etc.
               *
               * Emits a {Transfer} event.
               *
               * Requirements:
               *
               * - `sender` cannot be the zero address.
               * - `recipient` cannot be the zero address.
               * - `sender` must have a balance of at least `amount`.
               */
              function _transfer(address sender, address recipient, uint256 amount) internal {
                  require(sender != address(0), "ERC20: transfer from the zero address");
                  require(recipient != address(0), "ERC20: transfer to the zero address");
                  _balances[sender] = _balances[sender].sub(amount, "ERC20: transfer amount exceeds balance");
                  _balances[recipient] = _balances[recipient].add(amount);
                  emit Transfer(sender, recipient, amount);
              }
              /** @dev Creates `amount` tokens and assigns them to `account`, increasing
               * the total supply.
               *
               * Emits a {Transfer} event with `from` set to the zero address.
               *
               * Requirements
               *
               * - `to` cannot be the zero address.
               */
              function _mint(address account, uint256 amount) internal {
                  require(account != address(0), "ERC20: mint to the zero address");
                  _totalSupply = _totalSupply.add(amount);
                  _balances[account] = _balances[account].add(amount);
                  emit Transfer(address(0), account, amount);
              }
              /**
               * @dev Destroys `amount` tokens from `account`, reducing the
               * total supply.
               *
               * Emits a {Transfer} event with `to` set to the zero address.
               *
               * Requirements
               *
               * - `account` cannot be the zero address.
               * - `account` must have at least `amount` tokens.
               */
              function _burn(address account, uint256 amount) internal {
                  require(account != address(0), "ERC20: burn from the zero address");
                  _balances[account] = _balances[account].sub(amount, "ERC20: burn amount exceeds balance");
                  _totalSupply = _totalSupply.sub(amount);
                  emit Transfer(account, address(0), amount);
              }
              /**
               * @dev Sets `amount` as the allowance of `spender` over the `owner`s tokens.
               *
               * This is internal function is equivalent to `approve`, and can be used to
               * e.g. set automatic allowances for certain subsystems, etc.
               *
               * Emits an {Approval} event.
               *
               * Requirements:
               *
               * - `owner` cannot be the zero address.
               * - `spender` cannot be the zero address.
               */
              function _approve(address owner, address spender, uint256 amount) internal {
                  require(owner != address(0), "ERC20: approve from the zero address");
                  require(spender != address(0), "ERC20: approve to the zero address");
                  _allowances[owner][spender] = amount;
                  emit Approval(owner, spender, amount);
              }
              /**
               * @dev Destroys `amount` tokens from `account`.`amount` is then deducted
               * from the caller's allowance.
               *
               * See {_burn} and {_approve}.
               */
              function _burnFrom(address account, uint256 amount) internal {
                  _burn(account, amount);
                  _approve(account, _msgSender(), _allowances[account][_msgSender()].sub(amount, "ERC20: burn amount exceeds allowance"));
              }
          }
          pragma solidity ^0.5.0;
          import "openzeppelin-solidity/Context.sol";
          import "openzeppelin-solidity/Roles.sol";
          contract MinterRole is Context {
              using Roles for Roles.Role;
              event MinterAdded(address indexed account);
              event MinterRemoved(address indexed account);
              Roles.Role private _minters;
              constructor () internal {
                  _addMinter(_msgSender());
              }
              modifier onlyMinter() {
                  require(isMinter(_msgSender()), "MinterRole: caller does not have the Minter role");
                  _;
              }
              function isMinter(address account) public view returns (bool) {
                  return _minters.has(account);
              }
              function addMinter(address account) public onlyMinter {
                  _addMinter(account);
              }
              function renounceMinter() public {
                  _removeMinter(_msgSender());
              }
              function _addMinter(address account) internal {
                  _minters.add(account);
                  emit MinterAdded(account);
              }
              function _removeMinter(address account) internal {
                  _minters.remove(account);
                  emit MinterRemoved(account);
              }
          }
          pragma solidity ^0.5.0;
          /**
           * @title Roles
           * @dev Library for managing addresses assigned to a Role.
           */
          library Roles {
              struct Role {
                  mapping (address => bool) bearer;
              }
              /**
               * @dev Give an account access to this role.
               */
              function add(Role storage role, address account) internal {
                  require(!has(role, account), "Roles: account already has role");
                  role.bearer[account] = true;
              }
              /**
               * @dev Remove an account's access to this role.
               */
              function remove(Role storage role, address account) internal {
                  require(has(role, account), "Roles: account does not have role");
                  role.bearer[account] = false;
              }
              /**
               * @dev Check if an account has this role.
               * @return bool
               */
              function has(Role storage role, address account) internal view returns (bool) {
                  require(account != address(0), "Roles: account is the zero address");
                  return role.bearer[account];
              }
          }
          pragma solidity ^0.5.12;
          interface AutoRefactorCoinageI {
            function factor() external view returns (uint256);
            function setFactor(uint256 factor) external returns (bool);
            function burn(uint256 amount) external;
            function burnFrom(address account, uint256 amount) external;
            function mint(address account, uint256 amount) external returns (bool);
            function totalSupply() external view returns (uint256);
            function balanceOf(address account) external view returns (uint256);
            function addMinter(address account) external;
            function renounceMinter() external;
            function transferOwnership(address newOwner) external;
          }
          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 6 of 8: PowerTON
          // File: openzeppelin-solidity/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-solidity/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 {
                  address msgSender = _msgSender();
                  _owner = msgSender;
                  emit OwnershipTransferred(address(0), msgSender);
              }
          
              /**
               * @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-solidity/contracts/access/Roles.sol
          
          pragma solidity ^0.5.0;
          
          /**
           * @title Roles
           * @dev Library for managing addresses assigned to a Role.
           */
          library Roles {
              struct Role {
                  mapping (address => bool) bearer;
              }
          
              /**
               * @dev Give an account access to this role.
               */
              function add(Role storage role, address account) internal {
                  require(!has(role, account), "Roles: account already has role");
                  role.bearer[account] = true;
              }
          
              /**
               * @dev Remove an account's access to this role.
               */
              function remove(Role storage role, address account) internal {
                  require(has(role, account), "Roles: account does not have role");
                  role.bearer[account] = false;
              }
          
              /**
               * @dev Check if an account has this role.
               * @return bool
               */
              function has(Role storage role, address account) internal view returns (bool) {
                  require(account != address(0), "Roles: account is the zero address");
                  return role.bearer[account];
              }
          }
          
          // File: openzeppelin-solidity/contracts/access/roles/PauserRole.sol
          
          pragma solidity ^0.5.0;
          
          
          
          contract PauserRole is Context {
              using Roles for Roles.Role;
          
              event PauserAdded(address indexed account);
              event PauserRemoved(address indexed account);
          
              Roles.Role private _pausers;
          
              constructor () internal {
                  _addPauser(_msgSender());
              }
          
              modifier onlyPauser() {
                  require(isPauser(_msgSender()), "PauserRole: caller does not have the Pauser role");
                  _;
              }
          
              function isPauser(address account) public view returns (bool) {
                  return _pausers.has(account);
              }
          
              function addPauser(address account) public onlyPauser {
                  _addPauser(account);
              }
          
              function renouncePauser() public {
                  _removePauser(_msgSender());
              }
          
              function _addPauser(address account) internal {
                  _pausers.add(account);
                  emit PauserAdded(account);
              }
          
              function _removePauser(address account) internal {
                  _pausers.remove(account);
                  emit PauserRemoved(account);
              }
          }
          
          // File: openzeppelin-solidity/contracts/lifecycle/Pausable.sol
          
          pragma solidity ^0.5.0;
          
          
          
          /**
           * @dev Contract module which allows children to implement an emergency stop
           * mechanism that can be triggered by an authorized account.
           *
           * This module is used through inheritance. It will make available the
           * modifiers `whenNotPaused` and `whenPaused`, which can be applied to
           * the functions of your contract. Note that they will not be pausable by
           * simply including this module, only once the modifiers are put in place.
           */
          contract Pausable is Context, PauserRole {
              /**
               * @dev Emitted when the pause is triggered by a pauser (`account`).
               */
              event Paused(address account);
          
              /**
               * @dev Emitted when the pause is lifted by a pauser (`account`).
               */
              event Unpaused(address account);
          
              bool private _paused;
          
              /**
               * @dev Initializes the contract in unpaused state. Assigns the Pauser role
               * to the deployer.
               */
              constructor () internal {
                  _paused = false;
              }
          
              /**
               * @dev Returns true if the contract is paused, and false otherwise.
               */
              function paused() public view returns (bool) {
                  return _paused;
              }
          
              /**
               * @dev Modifier to make a function callable only when the contract is not paused.
               */
              modifier whenNotPaused() {
                  require(!_paused, "Pausable: paused");
                  _;
              }
          
              /**
               * @dev Modifier to make a function callable only when the contract is paused.
               */
              modifier whenPaused() {
                  require(_paused, "Pausable: not paused");
                  _;
              }
          
              /**
               * @dev Called by a pauser to pause, triggers stopped state.
               */
              function pause() public onlyPauser whenNotPaused {
                  _paused = true;
                  emit Paused(_msgSender());
              }
          
              /**
               * @dev Called by a pauser to unpause, returns to normal state.
               */
              function unpause() public onlyPauser whenPaused {
                  _paused = false;
                  emit Unpaused(_msgSender());
              }
          }
          
          // File: openzeppelin-solidity/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-solidity/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);
          
              /**
               * @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-solidity/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.
               *
               * [IMPORTANT]
               * ====
               * It is unsafe to assume that an address for which this function returns
               * false is an externally-owned account (EOA) and not a contract.
               *
               * Among others, `isContract` will return false for the following 
               * types of addresses:
               *
               *  - an externally-owned account
               *  - a contract in construction
               *  - an address where a contract will be created
               *  - an address where a contract lived, but was destroyed
               * ====
               */
              function isContract(address account) internal view returns (bool) {
                  // 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 != accountHash && codehash != 0x0);
              }
          
              /**
               * @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-solidity/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: openzeppelin-solidity/contracts/token/ERC20/ERC20.sol
          
          pragma solidity ^0.5.0;
          
          
          
          
          /**
           * @dev Implementation of the {IERC20} interface.
           *
           * This implementation is agnostic to the way tokens are created. This means
           * that a supply mechanism has to be added in a derived contract using {_mint}.
           * For a generic mechanism see {ERC20Mintable}.
           *
           * TIP: For a detailed writeup see our guide
           * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How
           * to implement supply mechanisms].
           *
           * We have followed general OpenZeppelin guidelines: functions revert instead
           * of returning `false` on failure. This behavior is nonetheless conventional
           * and does not conflict with the expectations of ERC20 applications.
           *
           * Additionally, an {Approval} event is emitted on calls to {transferFrom}.
           * This allows applications to reconstruct the allowance for all accounts just
           * by listening to said events. Other implementations of the EIP may not emit
           * these events, as it isn't required by the specification.
           *
           * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}
           * functions have been added to mitigate the well-known issues around setting
           * allowances. See {IERC20-approve}.
           */
          contract ERC20 is Context, IERC20 {
              using SafeMath for uint256;
          
              mapping (address => uint256) private _balances;
          
              mapping (address => mapping (address => uint256)) private _allowances;
          
              uint256 private _totalSupply;
          
              /**
               * @dev See {IERC20-totalSupply}.
               */
              function totalSupply() public view returns (uint256) {
                  return _totalSupply;
              }
          
              /**
               * @dev See {IERC20-balanceOf}.
               */
              function balanceOf(address account) public view returns (uint256) {
                  return _balances[account];
              }
          
              /**
               * @dev See {IERC20-transfer}.
               *
               * Requirements:
               *
               * - `recipient` cannot be the zero address.
               * - the caller must have a balance of at least `amount`.
               */
              function transfer(address recipient, uint256 amount) public returns (bool) {
                  _transfer(_msgSender(), recipient, amount);
                  return true;
              }
          
              /**
               * @dev See {IERC20-allowance}.
               */
              function allowance(address owner, address spender) public view returns (uint256) {
                  return _allowances[owner][spender];
              }
          
              /**
               * @dev See {IERC20-approve}.
               *
               * Requirements:
               *
               * - `spender` cannot be the zero address.
               */
              function approve(address spender, uint256 amount) public returns (bool) {
                  _approve(_msgSender(), spender, amount);
                  return true;
              }
          
              /**
               * @dev See {IERC20-transferFrom}.
               *
               * Emits an {Approval} event indicating the updated allowance. This is not
               * required by the EIP. See the note at the beginning of {ERC20};
               *
               * Requirements:
               * - `sender` and `recipient` cannot be the zero address.
               * - `sender` must have a balance of at least `amount`.
               * - the caller must have allowance for `sender`'s tokens of at least
               * `amount`.
               */
              function transferFrom(address sender, address recipient, uint256 amount) public returns (bool) {
                  _transfer(sender, recipient, amount);
                  _approve(sender, _msgSender(), _allowances[sender][_msgSender()].sub(amount, "ERC20: transfer amount exceeds allowance"));
                  return true;
              }
          
              /**
               * @dev Atomically increases the allowance granted to `spender` by the caller.
               *
               * This is an alternative to {approve} that can be used as a mitigation for
               * problems described in {IERC20-approve}.
               *
               * Emits an {Approval} event indicating the updated allowance.
               *
               * Requirements:
               *
               * - `spender` cannot be the zero address.
               */
              function increaseAllowance(address spender, uint256 addedValue) public returns (bool) {
                  _approve(_msgSender(), spender, _allowances[_msgSender()][spender].add(addedValue));
                  return true;
              }
          
              /**
               * @dev Atomically decreases the allowance granted to `spender` by the caller.
               *
               * This is an alternative to {approve} that can be used as a mitigation for
               * problems described in {IERC20-approve}.
               *
               * Emits an {Approval} event indicating the updated allowance.
               *
               * Requirements:
               *
               * - `spender` cannot be the zero address.
               * - `spender` must have allowance for the caller of at least
               * `subtractedValue`.
               */
              function decreaseAllowance(address spender, uint256 subtractedValue) public returns (bool) {
                  _approve(_msgSender(), spender, _allowances[_msgSender()][spender].sub(subtractedValue, "ERC20: decreased allowance below zero"));
                  return true;
              }
          
              /**
               * @dev Moves tokens `amount` from `sender` to `recipient`.
               *
               * This is internal function is equivalent to {transfer}, and can be used to
               * e.g. implement automatic token fees, slashing mechanisms, etc.
               *
               * Emits a {Transfer} event.
               *
               * Requirements:
               *
               * - `sender` cannot be the zero address.
               * - `recipient` cannot be the zero address.
               * - `sender` must have a balance of at least `amount`.
               */
              function _transfer(address sender, address recipient, uint256 amount) internal {
                  require(sender != address(0), "ERC20: transfer from the zero address");
                  require(recipient != address(0), "ERC20: transfer to the zero address");
          
                  _balances[sender] = _balances[sender].sub(amount, "ERC20: transfer amount exceeds balance");
                  _balances[recipient] = _balances[recipient].add(amount);
                  emit Transfer(sender, recipient, amount);
              }
          
              /** @dev Creates `amount` tokens and assigns them to `account`, increasing
               * the total supply.
               *
               * Emits a {Transfer} event with `from` set to the zero address.
               *
               * Requirements
               *
               * - `to` cannot be the zero address.
               */
              function _mint(address account, uint256 amount) internal {
                  require(account != address(0), "ERC20: mint to the zero address");
          
                  _totalSupply = _totalSupply.add(amount);
                  _balances[account] = _balances[account].add(amount);
                  emit Transfer(address(0), account, amount);
              }
          
              /**
               * @dev Destroys `amount` tokens from `account`, reducing the
               * total supply.
               *
               * Emits a {Transfer} event with `to` set to the zero address.
               *
               * Requirements
               *
               * - `account` cannot be the zero address.
               * - `account` must have at least `amount` tokens.
               */
              function _burn(address account, uint256 amount) internal {
                  require(account != address(0), "ERC20: burn from the zero address");
          
                  _balances[account] = _balances[account].sub(amount, "ERC20: burn amount exceeds balance");
                  _totalSupply = _totalSupply.sub(amount);
                  emit Transfer(account, address(0), amount);
              }
          
              /**
               * @dev Sets `amount` as the allowance of `spender` over the `owner`s tokens.
               *
               * This is internal function is equivalent to `approve`, and can be used to
               * e.g. set automatic allowances for certain subsystems, etc.
               *
               * Emits an {Approval} event.
               *
               * Requirements:
               *
               * - `owner` cannot be the zero address.
               * - `spender` cannot be the zero address.
               */
              function _approve(address owner, address spender, uint256 amount) internal {
                  require(owner != address(0), "ERC20: approve from the zero address");
                  require(spender != address(0), "ERC20: approve to the zero address");
          
                  _allowances[owner][spender] = amount;
                  emit Approval(owner, spender, amount);
              }
          
              /**
               * @dev Destroys `amount` tokens from `account`.`amount` is then deducted
               * from the caller's allowance.
               *
               * See {_burn} and {_approve}.
               */
              function _burnFrom(address account, uint256 amount) internal {
                  _burn(account, amount);
                  _approve(account, _msgSender(), _allowances[account][_msgSender()].sub(amount, "ERC20: burn amount exceeds allowance"));
              }
          }
          
          // File: openzeppelin-solidity/contracts/access/roles/MinterRole.sol
          
          pragma solidity ^0.5.0;
          
          
          
          contract MinterRole is Context {
              using Roles for Roles.Role;
          
              event MinterAdded(address indexed account);
              event MinterRemoved(address indexed account);
          
              Roles.Role private _minters;
          
              constructor () internal {
                  _addMinter(_msgSender());
              }
          
              modifier onlyMinter() {
                  require(isMinter(_msgSender()), "MinterRole: caller does not have the Minter role");
                  _;
              }
          
              function isMinter(address account) public view returns (bool) {
                  return _minters.has(account);
              }
          
              function addMinter(address account) public onlyMinter {
                  _addMinter(account);
              }
          
              function renounceMinter() public {
                  _removeMinter(_msgSender());
              }
          
              function _addMinter(address account) internal {
                  _minters.add(account);
                  emit MinterAdded(account);
              }
          
              function _removeMinter(address account) internal {
                  _minters.remove(account);
                  emit MinterRemoved(account);
              }
          }
          
          // File: openzeppelin-solidity/contracts/token/ERC20/ERC20Mintable.sol
          
          pragma solidity ^0.5.0;
          
          
          
          /**
           * @dev Extension of {ERC20} that adds a set of accounts with the {MinterRole},
           * which have permission to mint (create) new tokens as they see fit.
           *
           * At construction, the deployer of the contract is the only minter.
           */
          contract ERC20Mintable is ERC20, MinterRole {
              /**
               * @dev See {ERC20-_mint}.
               *
               * Requirements:
               *
               * - the caller must have the {MinterRole}.
               */
              function mint(address account, uint256 amount) public onlyMinter returns (bool) {
                  _mint(account, amount);
                  return true;
              }
          }
          
          // File: openzeppelin-solidity/contracts/token/ERC20/ERC20Burnable.sol
          
          pragma solidity ^0.5.0;
          
          
          
          /**
           * @dev Extension of {ERC20} that allows token holders to destroy both their own
           * tokens and those that they have an allowance for, in a way that can be
           * recognized off-chain (via event analysis).
           */
          contract ERC20Burnable is Context, ERC20 {
              /**
               * @dev Destroys `amount` tokens from the caller.
               *
               * See {ERC20-_burn}.
               */
              function burn(uint256 amount) public {
                  _burn(_msgSender(), amount);
              }
          
              /**
               * @dev See {ERC20-_burnFrom}.
               */
              function burnFrom(address account, uint256 amount) public {
                  _burnFrom(account, amount);
              }
          }
          
          // File: openzeppelin-solidity/contracts/token/ERC20/ERC20Detailed.sol
          
          pragma solidity ^0.5.0;
          
          
          /**
           * @dev Optional functions from the ERC20 standard.
           */
          contract ERC20Detailed is IERC20 {
              string private _name;
              string private _symbol;
              uint8 private _decimals;
          
              /**
               * @dev Sets the values for `name`, `symbol`, and `decimals`. All three of
               * these values are immutable: they can only be set once during
               * construction.
               */
              constructor (string memory name, string memory symbol, uint8 decimals) public {
                  _name = name;
                  _symbol = symbol;
                  _decimals = decimals;
              }
          
              /**
               * @dev Returns the name of the token.
               */
              function name() public view returns (string memory) {
                  return _name;
              }
          
              /**
               * @dev Returns the symbol of the token, usually a shorter version of the
               * name.
               */
              function symbol() public view returns (string memory) {
                  return _symbol;
              }
          
              /**
               * @dev Returns the number of decimals used to get its user representation.
               * For example, if `decimals` equals `2`, a balance of `505` tokens should
               * be displayed to a user as `5,05` (`505 / 10 ** 2`).
               *
               * Tokens usually opt for a value of 18, imitating the relationship between
               * Ether and Wei.
               *
               * NOTE: This information is only used for _display_ purposes: it in
               * no way affects any of the arithmetic of the contract, including
               * {IERC20-balanceOf} and {IERC20-transfer}.
               */
              function decimals() public view returns (uint8) {
                  return _decimals;
              }
          }
          
          // File: openzeppelin-solidity/contracts/utils/ReentrancyGuard.sol
          
          pragma solidity ^0.5.0;
          
          /**
           * @dev Contract module that helps prevent reentrant calls to a function.
           *
           * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
           * available, which can be applied to functions to make sure there are no nested
           * (reentrant) calls to them.
           *
           * Note that because there is a single `nonReentrant` guard, functions marked as
           * `nonReentrant` may not call one another. This can be worked around by making
           * those functions `private`, and then adding `external` `nonReentrant` entry
           * points to them.
           *
           * TIP: If you would like to learn more about reentrancy and alternative ways
           * to protect against it, check out our blog post
           * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
           *
           * _Since v2.5.0:_ this module is now much more gas efficient, given net gas
           * metering changes introduced in the Istanbul hardfork.
           */
          contract ReentrancyGuard {
              bool private _notEntered;
          
              constructor () internal {
                  // Storing an initial non-zero value makes deployment a bit more
                  // expensive, but in exchange the refund on every call to nonReentrant
                  // will be lower in amount. Since refunds are capped to a percetange of
                  // the total transaction's gas, it is best to keep them low in cases
                  // like this one, to increase the likelihood of the full refund coming
                  // into effect.
                  _notEntered = true;
              }
          
              /**
               * @dev Prevents a contract from calling itself, directly or indirectly.
               * Calling a `nonReentrant` function from another `nonReentrant`
               * function is not supported. It is possible to prevent this from happening
               * by making the `nonReentrant` function external, and make it call a
               * `private` function that does the actual work.
               */
              modifier nonReentrant() {
                  // On the first call to nonReentrant, _notEntered will be true
                  require(_notEntered, "ReentrancyGuard: reentrant call");
          
                  // Any calls to nonReentrant after this point will fail
                  _notEntered = false;
          
                  _;
          
                  // By storing the original value once again, a refund is triggered (see
                  // https://eips.ethereum.org/EIPS/eip-2200)
                  _notEntered = true;
              }
          }
          
          // File: openzeppelin-solidity/contracts/introspection/IERC165.sol
          
          pragma solidity ^0.5.0;
          
          /**
           * @dev Interface of the ERC165 standard, as defined in the
           * https://eips.ethereum.org/EIPS/eip-165[EIP].
           *
           * Implementers can declare support of contract interfaces, which can then be
           * queried by others ({ERC165Checker}).
           *
           * For an implementation, see {ERC165}.
           */
          interface IERC165 {
              /**
               * @dev Returns true if this contract implements the interface defined by
               * `interfaceId`. See the corresponding
               * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
               * to learn more about how these ids are created.
               *
               * This function call must use less than 30 000 gas.
               */
              function supportsInterface(bytes4 interfaceId) external view returns (bool);
          }
          
          // File: openzeppelin-solidity/contracts/introspection/ERC165.sol
          
          pragma solidity ^0.5.0;
          
          
          /**
           * @dev Implementation of the {IERC165} interface.
           *
           * Contracts may inherit from this and call {_registerInterface} to declare
           * their support of an interface.
           */
          contract ERC165 is IERC165 {
              /*
               * bytes4(keccak256('supportsInterface(bytes4)')) == 0x01ffc9a7
               */
              bytes4 private constant _INTERFACE_ID_ERC165 = 0x01ffc9a7;
          
              /**
               * @dev Mapping of interface ids to whether or not it's supported.
               */
              mapping(bytes4 => bool) private _supportedInterfaces;
          
              constructor () internal {
                  // Derived contracts need only register support for their own interfaces,
                  // we register support for ERC165 itself here
                  _registerInterface(_INTERFACE_ID_ERC165);
              }
          
              /**
               * @dev See {IERC165-supportsInterface}.
               *
               * Time complexity O(1), guaranteed to always use less than 30 000 gas.
               */
              function supportsInterface(bytes4 interfaceId) external view returns (bool) {
                  return _supportedInterfaces[interfaceId];
              }
          
              /**
               * @dev Registers the contract as an implementer of the interface defined by
               * `interfaceId`. Support of the actual ERC165 interface is automatic and
               * registering its interface id is not required.
               *
               * See {IERC165-supportsInterface}.
               *
               * Requirements:
               *
               * - `interfaceId` cannot be the ERC165 invalid interface (`0xffffffff`).
               */
              function _registerInterface(bytes4 interfaceId) internal {
                  require(interfaceId != 0xffffffff, "ERC165: invalid interface id");
                  _supportedInterfaces[interfaceId] = true;
              }
          }
          
          // File: openzeppelin-solidity/contracts/introspection/ERC165Checker.sol
          
          pragma solidity ^0.5.10;
          
          /**
           * @dev Library used to query support of an interface declared via {IERC165}.
           *
           * Note that these functions return the actual result of the query: they do not
           * `revert` if an interface is not supported. It is up to the caller to decide
           * what to do in these cases.
           */
          library ERC165Checker {
              // As per the EIP-165 spec, no interface should ever match 0xffffffff
              bytes4 private constant _INTERFACE_ID_INVALID = 0xffffffff;
          
              /*
               * bytes4(keccak256('supportsInterface(bytes4)')) == 0x01ffc9a7
               */
              bytes4 private constant _INTERFACE_ID_ERC165 = 0x01ffc9a7;
          
              /**
               * @dev Returns true if `account` supports the {IERC165} interface,
               */
              function _supportsERC165(address account) internal view returns (bool) {
                  // Any contract that implements ERC165 must explicitly indicate support of
                  // InterfaceId_ERC165 and explicitly indicate non-support of InterfaceId_Invalid
                  return _supportsERC165Interface(account, _INTERFACE_ID_ERC165) &&
                      !_supportsERC165Interface(account, _INTERFACE_ID_INVALID);
              }
          
              /**
               * @dev Returns true if `account` supports the interface defined by
               * `interfaceId`. Support for {IERC165} itself is queried automatically.
               *
               * See {IERC165-supportsInterface}.
               */
              function _supportsInterface(address account, bytes4 interfaceId) internal view returns (bool) {
                  // query support of both ERC165 as per the spec and support of _interfaceId
                  return _supportsERC165(account) &&
                      _supportsERC165Interface(account, interfaceId);
              }
          
              /**
               * @dev Returns true if `account` supports all the interfaces defined in
               * `interfaceIds`. Support for {IERC165} itself is queried automatically.
               *
               * Batch-querying can lead to gas savings by skipping repeated checks for
               * {IERC165} support.
               *
               * See {IERC165-supportsInterface}.
               */
              function _supportsAllInterfaces(address account, bytes4[] memory interfaceIds) internal view returns (bool) {
                  // query support of ERC165 itself
                  if (!_supportsERC165(account)) {
                      return false;
                  }
          
                  // query support of each interface in _interfaceIds
                  for (uint256 i = 0; i < interfaceIds.length; i++) {
                      if (!_supportsERC165Interface(account, interfaceIds[i])) {
                          return false;
                      }
                  }
          
                  // all interfaces supported
                  return true;
              }
          
              /**
               * @notice Query if a contract implements an interface, does not check ERC165 support
               * @param account The address of the contract to query for support of an interface
               * @param interfaceId The interface identifier, as specified in ERC-165
               * @return true if the contract at account indicates support of the interface with
               * identifier interfaceId, false otherwise
               * @dev Assumes that account contains a contract that supports ERC165, otherwise
               * the behavior of this method is undefined. This precondition can be checked
               * with the `supportsERC165` method in this library.
               * Interface identification is specified in ERC-165.
               */
              function _supportsERC165Interface(address account, bytes4 interfaceId) private view returns (bool) {
                  // success determines whether the staticcall succeeded and result determines
                  // whether the contract at account indicates support of _interfaceId
                  (bool success, bool result) = _callERC165SupportsInterface(account, interfaceId);
          
                  return (success && result);
              }
          
              /**
               * @notice Calls the function with selector 0x01ffc9a7 (ERC165) and suppresses throw
               * @param account The address of the contract to query for support of an interface
               * @param interfaceId The interface identifier, as specified in ERC-165
               * @return success true if the STATICCALL succeeded, false otherwise
               * @return result true if the STATICCALL succeeded and the contract at account
               * indicates support of the interface with identifier interfaceId, false otherwise
               */
              function _callERC165SupportsInterface(address account, bytes4 interfaceId)
                  private
                  view
                  returns (bool, bool)
              {
                  bytes memory encodedParams = abi.encodeWithSelector(_INTERFACE_ID_ERC165, interfaceId);
                  (bool success, bytes memory result) = account.staticcall.gas(30000)(encodedParams);
                  if (result.length < 32) return (false, false);
                  return (success, abi.decode(result, (bool)));
              }
          }
          
          // File: coinage-token/contracts/lib/DSMath.sol
          
          // https://github.com/dapphub/ds-math/blob/de45767/src/math.sol
          /// math.sol -- mixin for inline numerical wizardry
          
          // This program is free software: you can redistribute it and/or modify
          // it under the terms of the GNU General Public License as published by
          // the Free Software Foundation, either version 3 of the License, or
          // (at your option) any later version.
          
          // This program is distributed in the hope that it will be useful,
          // but WITHOUT ANY WARRANTY; without even the implied warranty of
          // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
          // GNU General Public License for more details.
          
          // You should have received a copy of the GNU General Public License
          // along with this program.  If not, see <http://www.gnu.org/licenses/>.
          
          pragma solidity >0.4.13;
          
          contract DSMath {
            function add(uint x, uint y) internal pure returns (uint z) {
              require((z = x + y) >= x, "ds-math-add-overflow");
            }
            function sub(uint x, uint y) internal pure returns (uint z) {
              require((z = x - y) <= x, "ds-math-sub-underflow");
            }
            function mul(uint x, uint y) internal pure returns (uint z) {
              require(y == 0 || (z = x * y) / y == x, "ds-math-mul-overflow");
            }
          
            function min(uint x, uint y) internal pure returns (uint z) {
              return x <= y ? x : y;
            }
            function max(uint x, uint y) internal pure returns (uint z) {
              return x >= y ? x : y;
            }
            function imin(int x, int y) internal pure returns (int z) {
              return x <= y ? x : y;
            }
            function imax(int x, int y) internal pure returns (int z) {
              return x >= y ? x : y;
            }
          
            uint constant WAD = 10 ** 18;
            uint constant RAY = 10 ** 27;
          
            function wmul(uint x, uint y) internal pure returns (uint z) {
              z = add(mul(x, y), WAD / 2) / WAD;
            }
            function rmul(uint x, uint y) internal pure returns (uint z) {
              z = add(mul(x, y), RAY / 2) / RAY;
            }
            function wdiv(uint x, uint y) internal pure returns (uint z) {
              z = add(mul(x, WAD), y / 2) / y;
            }
            function rdiv(uint x, uint y) internal pure returns (uint z) {
              z = add(mul(x, RAY), y / 2) / y;
            }
          
            // This famous algorithm is called "exponentiation by squaring"
            // and calculates x^n with x as fixed-point and n as regular unsigned.
            //
            // It's O(log n), instead of O(n) for naive repeated multiplication.
            //
            // These facts are why it works:
            //
            //  If n is even, then x^n = (x^2)^(n/2).
            //  If n is odd,  then x^n = x * x^(n-1),
            //   and applying the equation for even x gives
            //  x^n = x * (x^2)^((n-1) / 2).
            //
            //  Also, EVM division is flooring and
            //  floor[(n-1) / 2] = floor[n / 2].
            //
            function wpow(uint x, uint n) internal pure returns (uint z) {
              z = n % 2 != 0 ? x : WAD;
          
              for (n /= 2; n != 0; n /= 2) {
                x = wmul(x, x);
          
                if (n % 2 != 0) {
                  z = wmul(z, x);
                }
              }
            }
          
            function rpow(uint x, uint n) internal pure returns (uint z) {
              z = n % 2 != 0 ? x : RAY;
          
              for (n /= 2; n != 0; n /= 2) {
                x = rmul(x, x);
          
                if (n % 2 != 0) {
                  z = rmul(z, x);
                }
              }
            }
          }
          
          // File: contracts/stake/interfaces/SeigManagerI.sol
          
          pragma solidity ^0.5.12;
          
          
          interface SeigManagerI {
            function registry() external view returns (address);
            function depositManager() external view returns (address);
            function ton() external view returns (address);
            function wton() external view returns (address);
            function powerton() external view returns (address);
            function tot() external view returns (address);
            function coinages(address layer2) external view returns (address);
            function commissionRates(address layer2) external view returns (uint256);
          
            function lastCommitBlock(address layer2) external view returns (uint256);
            function seigPerBlock() external view returns (uint256);
            function lastSeigBlock() external view returns (uint256);
            function pausedBlock() external view returns (uint256);
            function unpausedBlock() external view returns (uint256);
            function DEFAULT_FACTOR() external view returns (uint256);
          
            function deployCoinage(address layer2) external returns (bool);
            function setCommissionRate(address layer2, uint256 commission, bool isCommissionRateNegative) external returns (bool);
          
            function uncomittedStakeOf(address layer2, address account) external view returns (uint256);
            function stakeOf(address layer2, address account) external view returns (uint256);
            function additionalTotBurnAmount(address layer2, address account, uint256 amount) external view returns (uint256 totAmount);
          
            function onTransfer(address sender, address recipient, uint256 amount) external returns (bool);
            function updateSeigniorage() external returns (bool);
            function onDeposit(address layer2, address account, uint256 amount) external returns (bool);
            function onWithdraw(address layer2, address account, uint256 amount) external returns (bool);
          
          }
          
          // File: contracts/stake/tokens/OnApprove.sol
          
          pragma solidity ^0.5.12;
          
          
          contract OnApprove is ERC165 {
            constructor() public {
              _registerInterface(OnApprove(this).onApprove.selector);
            }
          
            function onApprove(address owner, address spender, uint256 amount, bytes calldata data) external returns (bool);
          }
          
          // File: contracts/stake/tokens/ERC20OnApprove.sol
          
          pragma solidity ^0.5.12;
          
          
          
          
          
          contract ERC20OnApprove is ERC20 {
            function approveAndCall(address spender, uint256 amount, bytes memory data) public returns (bool) {
              require(approve(spender, amount));
              _callOnApprove(msg.sender, spender, amount, data);
              return true;
            }
          
            function _callOnApprove(address owner, address spender, uint256 amount, bytes memory data) internal {
              bytes4 onApproveSelector = OnApprove(spender).onApprove.selector;
          
              require(ERC165Checker._supportsInterface(spender, onApproveSelector),
                "ERC20OnApprove: spender doesn't support onApprove");
          
              (bool ok, bytes memory res) = spender.call(
                abi.encodeWithSelector(
                  onApproveSelector,
                  owner,
                  spender,
                  amount,
                  data
                )
              );
          
              // check if low-level call reverted or not
              require(ok, string(res));
          
              assembly {
                ok := mload(add(res, 0x20))
              }
          
              // check if OnApprove.onApprove returns true or false
              require(ok, "ERC20OnApprove: failed to call onApprove");
            }
          
          }
          
          // File: contracts/stake/tokens/AuthController.sol
          
          pragma solidity ^0.5.12;
          
          
          
          interface MinterRoleRenounceTarget {
            function renounceMinter() external;
          }
          
          interface PauserRoleRenounceTarget {
            function renouncePauser() external;
          }
          
          interface OwnableTarget {
            function renounceOwnership() external;
            function transferOwnership(address newOwner) external;
          }
          
          contract AuthController is Ownable {
            function renounceMinter(address target) public onlyOwner {
              MinterRoleRenounceTarget(target).renounceMinter();
            }
          
            function renouncePauser(address target) public onlyOwner {
              PauserRoleRenounceTarget(target).renouncePauser();
            }
          
            function renounceOwnership(address target) public onlyOwner {
              OwnableTarget(target).renounceOwnership();
            }
          
            function transferOwnership(address target, address newOwner) public onlyOwner {
              OwnableTarget(target).transferOwnership(newOwner);
            }
          }
          
          // File: contracts/stake/tokens/SeigToken.sol
          
          pragma solidity ^0.5.12;
          
          
          
          
          
          
          
          contract SeigToken is ERC20, Ownable, ERC20OnApprove, AuthController {
            SeigManagerI public seigManager;
            bool public callbackEnabled;
          
            function enableCallback(bool _callbackEnabled) external onlyOwner {
              callbackEnabled = _callbackEnabled;
            }
          
            function setSeigManager(SeigManagerI _seigManager) external onlyOwner {
              seigManager = _seigManager;
            }
          
            //////////////////////
            // Override ERC20 functions
            //////////////////////
          
            function transferFrom(address sender, address recipient, uint256 amount) public returns (bool) {
              return super.transferFrom(sender, recipient, amount);
            }
          
            function _transfer(address sender, address recipient, uint256 amount) internal {
              super._transfer(sender, recipient, amount);
              if (callbackEnabled && address(seigManager) != address(0)) {
                require(seigManager.onTransfer(sender, recipient, amount));
              }
            }
          
            function _mint(address account, uint256 amount) internal {
              super._mint(account, amount);
              if (callbackEnabled && address(seigManager) != address(0)) {
                require(seigManager.onTransfer(address(0), account, amount));
              }
            }
          
            function _burn(address account, uint256 amount) internal {
              super._burn(account, amount);
              if (callbackEnabled && address(seigManager) != address(0)) {
                require(seigManager.onTransfer(account, address(0), amount));
              }
            }
          }
          
          // File: contracts/stake/tokens/WTON.sol
          
          pragma solidity ^0.5.12;
          
          
          
          
          
          
          
          
          
          
          
          
          
          
          
          
          
          contract WTON is DSMath, ReentrancyGuard, Ownable, ERC20Mintable, ERC20Burnable, ERC20Detailed, SeigToken, OnApprove {
            using SafeERC20 for ERC20Mintable;
          
            ERC20Mintable public ton;
          
            constructor (
              ERC20Mintable _ton
            )
              public
              ERC20Detailed("Wrapped TON", "WTON", 27)
            {
              require(ERC20Detailed(address(_ton)).decimals() == 18, "WTON: decimals of TON must be 18");
              ton = _ton;
            }
          
            //////////////////////
            // TON Approve callback
            //////////////////////
          
            function onApprove(
              address owner,
              address spender,
              uint256 tonAmount,
              bytes calldata data
            ) external returns (bool) {
              require(msg.sender == address(ton), "WTON: only accept TON approve callback");
          
              // swap owner's TON to WTON
              _swapFromTON(owner, owner, tonAmount);
          
              uint256 wtonAmount = _toRAY(tonAmount);
              (address depositManager, address layer2) = _decodeTONApproveData(data);
          
              // approve WTON to DepositManager
              _approve(owner, depositManager, wtonAmount);
          
              // call DepositManager.onApprove to deposit WTON
              bytes memory depositManagerOnApproveData = _encodeDepositManagerOnApproveData(layer2);
              _callOnApprove(owner, depositManager, wtonAmount, depositManagerOnApproveData);
          
              return true;
            }
          
            /**
             * @dev data is 64 bytes of 2 addresses in left-padded 32 bytes
             */
            function _decodeTONApproveData(
              bytes memory data
            ) internal pure returns (address depositManager, address layer2) {
              require(data.length == 0x40);
          
              assembly {
                depositManager := mload(add(data, 0x20))
                layer2 := mload(add(data, 0x40))
              }
            }
          
            function _encodeDepositManagerOnApproveData(
              address layer2
            ) internal pure returns (bytes memory data) {
              data = new bytes(0x20);
          
              assembly {
                mstore(add(data, 0x20), layer2)
              }
            }
          
          
            //////////////////////
            // Override ERC20 functions
            //////////////////////
          
            function burnFrom(address account, uint256 amount) public {
              if (isMinter(msg.sender)) {
                _burn(account, amount);
                return;
              }
          
              super.burnFrom(account, amount);
            }
          
            //////////////////////
            // Swap functions
            //////////////////////
          
            /**
             * @dev swap WTON to TON
             */
            function swapToTON(uint256 wtonAmount) public nonReentrant returns (bool) {
              return _swapToTON(msg.sender, msg.sender, wtonAmount);
            }
          
            /**
             * @dev swap TON to WTON
             */
            function swapFromTON(uint256 tonAmount) public nonReentrant returns (bool) {
              return _swapFromTON(msg.sender, msg.sender, tonAmount);
            }
          
            /**
             * @dev swap WTON to TON, and transfer TON
             * NOTE: TON's transfer event's `from` argument is not `msg.sender` but `WTON` address.
             */
            function swapToTONAndTransfer(address to, uint256 wtonAmount) public nonReentrant returns (bool) {
              return _swapToTON(to, msg.sender, wtonAmount);
            }
          
            /**
             * @dev swap TON to WTON, and transfer WTON
             */
            function swapFromTONAndTransfer(address to, uint256 tonAmount) public nonReentrant returns (bool) {
              return _swapFromTON(msg.sender, to, tonAmount);
            }
          
            function renounceTonMinter() external onlyOwner {
              ton.renounceMinter();
            }
          
            //////////////////////
            // Internal functions
            //////////////////////
          
            function _swapToTON(address tonAccount, address wtonAccount, uint256 wtonAmount) internal returns (bool) {
              _burn(wtonAccount, wtonAmount);
          
              // mint TON if WTON contract has not enough TON to transfer
              uint256 tonAmount = _toWAD(wtonAmount);
              uint256 tonBalance = ton.balanceOf(address(this));
              if (tonBalance < tonAmount) {
                ton.mint(address(this), tonAmount.sub(tonBalance));
              }
          
              ton.safeTransfer(tonAccount, tonAmount);
              return true;
            }
          
            function _swapFromTON(address tonAccount, address wtonAccount, uint256 tonAmount) internal returns (bool) {
              _mint(wtonAccount, _toRAY(tonAmount));
              ton.safeTransferFrom(tonAccount, address(this), tonAmount);
              return true;
            }
          
            /**
             * @dev transform WAD to RAY
             */
            function _toRAY(uint256 v) internal pure returns (uint256) {
              return v * 10 ** 9;
            }
          
            /**
             * @dev transform RAY to WAD
             */
            function _toWAD(uint256 v) internal pure returns (uint256) {
              return v / 10 ** 9;
            }
          }
          
          // File: contracts/lib/SortitionSumTreeFactory.sol
          
          // https://github.com/kleros/kleros/blob/683145a9e6de70f5be87599daaf7372578b9d110/contracts/data-structures/SortitionSumTreeFactory.sol
          
          /**
           *  @reviewers: [@clesaege, @unknownunknown1, @ferittuncer]
           *  @auditors: []
           *  @bounties: [<14 days 10 ETH max payout>]
           *  @deployments: []
           */
          
          pragma solidity ^0.5.12;
          
          /**
           *  @title SortitionSumTreeFactory
           *  @author Enrique Piqueras - <[email protected]>
           *  @dev A factory of trees that keep track of staked values for sortition.
           */
          library SortitionSumTreeFactory {
            /* Structs */
          
            struct SortitionSumTree {
              uint K; // The maximum number of childs per node.
              // We use this to keep track of vacant positions in the tree after removing a leaf. This is for keeping the tree as balanced as possible without spending gas on moving nodes around.
              uint[] stack;
              uint[] nodes;
              // Two-way mapping of IDs to node indexes. Note that node index 0 is reserved for the root node, and means the ID does not have a node.
              mapping(bytes32 => uint) IDsToNodeIndexes;
              mapping(uint => bytes32) nodeIndexesToIDs;
            }
          
            /* Storage */
          
            struct SortitionSumTrees {
              mapping(bytes32 => SortitionSumTree) sortitionSumTrees;
            }
          
            /* Public */
          
            /**
             *  @dev Create a sortition sum tree at the specified key.
             *  @param _key The key of the new tree.
             *  @param _K The number of children each node in the tree should have.
             */
            function createTree(SortitionSumTrees storage self, bytes32 _key, uint _K) internal {
              SortitionSumTree storage tree = self.sortitionSumTrees[_key];
              require(tree.K == 0, "Tree already exists.");
              require(_K > 1, "K must be greater than one.");
              tree.K = _K;
              tree.stack.length = 0;
              tree.nodes.length = 0;
              tree.nodes.push(0);
            }
          
            /**
             *  @dev Set a value of a tree.
             *  @param _key The key of the tree.
             *  @param _value The new value.
             *  @param _ID The ID of the value.
             *  `O(log_k(n))` where
             *  `k` is the maximum number of childs per node in the tree,
             *   and `n` is the maximum number of nodes ever appended.
             */
            function set(SortitionSumTrees storage self, bytes32 _key, uint _value, bytes32 _ID) internal {
              SortitionSumTree storage tree = self.sortitionSumTrees[_key];
              uint treeIndex = tree.IDsToNodeIndexes[_ID];
          
              if (treeIndex == 0) { // No existing node.
                if (_value != 0) { // Non zero value.
                  // Append.
                  // Add node.
                  if (tree.stack.length == 0) { // No vacant spots.
                    // Get the index and append the value.
                    treeIndex = tree.nodes.length;
                    tree.nodes.push(_value);
          
                    // Potentially append a new node and make the parent a sum node.
                    if (treeIndex != 1 && (treeIndex - 1) % tree.K == 0) { // Is first child.
                      uint parentIndex = treeIndex / tree.K;
                      bytes32 parentID = tree.nodeIndexesToIDs[parentIndex];
                      uint newIndex = treeIndex + 1;
                      tree.nodes.push(tree.nodes[parentIndex]);
                      delete tree.nodeIndexesToIDs[parentIndex];
                      tree.IDsToNodeIndexes[parentID] = newIndex;
                      tree.nodeIndexesToIDs[newIndex] = parentID;
                    }
                  } else { // Some vacant spot.
                    // Pop the stack and append the value.
                    treeIndex = tree.stack[tree.stack.length - 1];
                    tree.stack.length--;
                    tree.nodes[treeIndex] = _value;
                  }
          
                  // Add label.
                  tree.IDsToNodeIndexes[_ID] = treeIndex;
                  tree.nodeIndexesToIDs[treeIndex] = _ID;
          
                  updateParents(self, _key, treeIndex, true, _value);
                }
              } else { // Existing node.
                if (_value == 0) { // Zero value.
                  // Remove.
                  // Remember value and set to 0.
                  uint value = tree.nodes[treeIndex];
                  tree.nodes[treeIndex] = 0;
          
                  // Push to stack.
                  tree.stack.push(treeIndex);
          
                  // Clear label.
                  delete tree.IDsToNodeIndexes[_ID];
                  delete tree.nodeIndexesToIDs[treeIndex];
          
                  updateParents(self, _key, treeIndex, false, value);
                } else if (_value != tree.nodes[treeIndex]) { // New, non zero value.
                  // Set.
                  bool plusOrMinus = tree.nodes[treeIndex] <= _value;
                  uint plusOrMinusValue = plusOrMinus ? _value - tree.nodes[treeIndex] : tree.nodes[treeIndex] - _value;
                  tree.nodes[treeIndex] = _value;
          
                  updateParents(self, _key, treeIndex, plusOrMinus, plusOrMinusValue);
                }
              }
            }
          
            /* Public Views */
          
            /**
             *  @dev Query the leaves of a tree. Note that if `startIndex == 0`, the tree is empty and the root node will be returned.
             *  @param _key The key of the tree to get the leaves from.
             *  @param _cursor The pagination cursor.
             *  @param _count The number of items to return.
             *  @return The index at which leaves start, the values of the returned leaves, and whether there are more for pagination.
             *  `O(n)` where
             *  `n` is the maximum number of nodes ever appended.
             */
            function queryLeafs(
              SortitionSumTrees storage self,
              bytes32 _key,
              uint _cursor,
              uint _count
            ) internal view returns(uint startIndex, uint[] memory values, bool hasMore) {
              SortitionSumTree storage tree = self.sortitionSumTrees[_key];
          
              // Find the start index.
              for (uint i = 0; i < tree.nodes.length; i++) {
                if ((tree.K * i) + 1 >= tree.nodes.length) {
                  startIndex = i;
                  break;
                }
              }
          
              // Get the values.
              uint loopStartIndex = startIndex + _cursor;
              values = new uint[](loopStartIndex + _count > tree.nodes.length ? tree.nodes.length - loopStartIndex : _count);
              uint valuesIndex = 0;
              for (uint j = loopStartIndex; j < tree.nodes.length; j++) {
                if (valuesIndex < _count) {
                  values[valuesIndex] = tree.nodes[j];
                  valuesIndex++;
                } else {
                  hasMore = true;
                  break;
                }
              }
            }
          
            /**
             *  @dev Draw an ID from a tree using a number. Note that this function reverts if the sum of all values in the tree is 0.
             *  @param _key The key of the tree.
             *  @param _drawnNumber The drawn number.
             *  @return The drawn ID.
             *  `O(k * log_k(n))` where
             *  `k` is the maximum number of childs per node in the tree,
             *   and `n` is the maximum number of nodes ever appended.
             */
            function draw(SortitionSumTrees storage self, bytes32 _key, uint _drawnNumber) internal view returns(bytes32 ID) {
              SortitionSumTree storage tree = self.sortitionSumTrees[_key];
              uint treeIndex = 0;
              uint currentDrawnNumber = _drawnNumber % tree.nodes[0];
          
              while ((tree.K * treeIndex) + 1 < tree.nodes.length)  // While it still has children.
                for (uint i = 1; i <= tree.K; i++) { // Loop over children.
                  uint nodeIndex = (tree.K * treeIndex) + i;
                  uint nodeValue = tree.nodes[nodeIndex];
          
                  if (currentDrawnNumber >= nodeValue) currentDrawnNumber -= nodeValue; // Go to the next child.
                  else { // Pick this child.
                    treeIndex = nodeIndex;
                    break;
                  }
                }
          
              ID = tree.nodeIndexesToIDs[treeIndex];
            }
          
            /** @dev Gets a specified ID's associated value.
             *  @param _key The key of the tree.
             *  @param _ID The ID of the value.
             *  @return The associated value.
             */
            function stakeOf(SortitionSumTrees storage self, bytes32 _key, bytes32 _ID) internal view returns(uint value) {
              SortitionSumTree storage tree = self.sortitionSumTrees[_key];
              uint treeIndex = tree.IDsToNodeIndexes[_ID];
          
              if (treeIndex == 0) value = 0;
              else value = tree.nodes[treeIndex];
            }
          
            /* Private */
          
            /**
             *  @dev Update all the parents of a node.
             *  @param _key The key of the tree to update.
             *  @param _treeIndex The index of the node to start from.
             *  @param _plusOrMinus Wether to add (true) or substract (false).
             *  @param _value The value to add or substract.
             *  `O(log_k(n))` where
             *  `k` is the maximum number of childs per node in the tree,
             *   and `n` is the maximum number of nodes ever appended.
             */
            function updateParents(SortitionSumTrees storage self, bytes32 _key, uint _treeIndex, bool _plusOrMinus, uint _value) private {
              SortitionSumTree storage tree = self.sortitionSumTrees[_key];
          
              uint parentIndex = _treeIndex;
              while (parentIndex != 0) {
                parentIndex = (parentIndex - 1) / tree.K;
                tree.nodes[parentIndex] = _plusOrMinus ? tree.nodes[parentIndex] + _value : tree.nodes[parentIndex] - _value;
              }
            }
          }
          
          // File: contracts/stake/interfaces/DepositManagerI.sol
          
          pragma solidity ^0.5.12;
          
          
          interface DepositManagerI {
            function owner() external view returns (address);
            function wton() external view returns (address);
            function registry() external view returns (address);
            function seigManager() external view returns (address);
          
            function accStaked(address layer2, address account) external view returns (uint256 wtonAmount);
            function accStakedLayer2(address layer2) external view returns (uint256 wtonAmount);
            function accStakedAccount(address account) external view returns (uint256 wtonAmount);
          
            function pendingUnstaked(address layer2, address account) external view returns (uint256 wtonAmount);
            function pendingUnstakedLayer2(address layer2) external view returns (uint256 wtonAmount);
            function pendingUnstakedAccount(address account) external view returns (uint256 wtonAmount);
          
            function accUnstaked(address layer2, address account) external view returns (uint256 wtonAmount);
            function accUnstakedLayer2(address layer2) external view returns (uint256 wtonAmount);
            function accUnstakedAccount(address account) external view returns (uint256 wtonAmount);
          
          
            function withdrawalRequestIndex(address layer2, address account) external view returns (uint256 index);
            function withdrawalRequest(address layer2, address account, uint256 index) external view returns (uint128 withdrawableBlockNumber, uint128 amount, bool processed );
          
            function WITHDRAWAL_DELAY() external view returns (uint256);
          
            function setSeigManager(address seigManager) external;
            function deposit(address layer2, uint256 amount) external returns (bool);
            function requestWithdrawal(address layer2, uint256 amount) external returns (bool);
            function processRequest(address layer2) external returns (bool);
            function requestWithdrawalAll(address layer2) external returns (bool);
            function processRequests(address layer2, uint256 n) external returns (bool);
          
            function numRequests(address layer2, address account) external view returns (uint256);
            function numPendingRequests(address layer2, address account) external view returns (uint256);
          
            function slash(address layer2, address recipient, uint256 amount) external returns (bool);
          }
          
          // File: contracts/stake/interfaces/PowerTONI.sol
          
          pragma solidity ^0.5.12;
          
          
          interface PowerTONI {
            function seigManager() external view returns (address);
            function wton() external view returns (address);
          
            function currentRound() external view returns (uint256);
            function roundDuration() external view returns (uint256);
            function totalDeposits() external view returns (uint256);
          
            function winnerOf(uint256 round) external view returns (address);
            function powerOf(address account) external view returns (uint256);
          
            function init() external;
            function start() external;
            function endRound() external;
          
            function onDeposit(address layer2, address account, uint256 amount) external;
            function onWithdraw(address layer2, address account, uint256 amount) external;
          }
          
          // File: contracts/stake/powerton/PowerTON.sol
          
          pragma solidity ^0.5.12;
          pragma experimental ABIEncoderV2;
          
          
          
          
          
          
          
          
          
          
          
          contract PowerTON is Ownable, Pausable, AuthController, PowerTONI {
            using SafeMath for *;
            using SafeERC20 for IERC20;
            using SortitionSumTreeFactory for SortitionSumTreeFactory.SortitionSumTrees;
          
            struct Round {
              uint64  startTime;
              uint64  endTime;
              uint256 reward;
              address winner;
            }
          
            // contracts
            address internal _seigManager;
            address internal _wton;
          
            // rounds
            uint256 internal _currentRound;
            // TODO: consider block nubmer
            uint256 internal _roundDuration; // unix timestamp
            mapping(uint256 => Round) public rounds;
          
            // sortition
            SortitionSumTreeFactory.SortitionSumTrees internal sortitionSumTrees;
            bool public initialized;
          
            bytes32 constant internal TREE_KEY = keccak256("power-balances");
            bytes32 constant internal TREE_KEY_PREFIX = keccak256("power-balances");
            uint256 constant internal TREE_NUM_CHILDREN = 16;
          
            // balances
            uint256 internal _totalDeposits;
          
            // randomness
            uint256 internal constant maskLast8Bits = uint256(0xff);
            uint256 internal constant maskFirst248Bits = uint256(~0xff);
          
          
            //////////////////////////////
            // Modifiers
            //////////////////////////////
          
            modifier checkRound() {
              if (currentRoundFinished()) {
                _endRound();
              }
              _;
            }
          
            //////////////////////////////
            // Events
            //////////////////////////////
          
            event RoundStart(uint256 round, uint256 startTime, uint256 endTime);
            event RoundEnd(uint256 round, address winner, uint256 reward);
            event PowerIncreased(address indexed account, uint256 amount);
            event PowerDecreased(address indexed account, uint256 amount);
          
            //////////////////////////////
            // Constructor
            //////////////////////////////
          
            constructor (
              address seigManager,
              address wton,
              uint256 roundDuration
            ) public {
              require(roundDuration > 0);
          
              _seigManager = seigManager;
              _wton = wton;
              _roundDuration = roundDuration;
            }
          
            /**
             * @dev set SeigManager contract, only by owner.
             */
            function setSeigManager(address seigManager) external onlyOwner {
              _seigManager = seigManager;
            }
          
            function init() external onlyOwner {
              require(!initialized);
              sortitionSumTrees.createTree(TREE_KEY, TREE_NUM_CHILDREN);
              initialized = true;
            }
          
            function start() external onlyOwner {
              require(_currentRound == 0, "PowerTON: current round is not zero");
              require(rounds[_currentRound].startTime == 0 && rounds[_currentRound].endTime == 0, "PowerTON: round already started");
              _startRound(0);
            }
          
            function powerOf(address account) external view returns (uint256) {
              return sortitionSumTrees.stakeOf(TREE_KEY, _getID(account));
            }
          
            /**
             * @dev end current round
             */
            function endRound() external {
              require(currentRoundFinished(), "PowerTON: round not finished");
              _endRound();
            }
          
            function roundStarted(uint256 round) public view returns (bool) {
              return rounds[round].startTime != 0 && rounds[round].endTime != 0;
            }
          
            function roundFinished(uint256 round) public view returns (bool) {
              return roundStarted(round) &&
                rounds[round].endTime < block.timestamp &&
                rounds[round].winner == address(0);
            }
          
            function currentRoundFinished() public view returns (bool) {
              return roundFinished(_currentRound);
            }
          
            function _endRound() internal {
              // short circuit in case of no deposit
              if (_totalDeposits == 0) {
                return;
              }
          
              uint256 round = _currentRound;
              Round storage r = rounds[round];
          
              uint256 n = _seed(block.number - 1) % _totalDeposits;
              address winner = _recoverID(sortitionSumTrees.draw(TREE_KEY, n));
              require(winner != address(0), "PowerTON: no winner");
              r.winner = winner;
          
          
              uint256 reward = IERC20(_wton).balanceOf(address(this));
          
              r.reward = reward;
          
              emit RoundEnd(round, winner, reward);
          
              _currentRound += 1;
              _startRound(_currentRound);
          
              WTON(_wton).swapToTONAndTransfer(winner, reward);
            }
          
            //////////////////////////////
            // SeigManager
            //////////////////////////////
          
            function onDeposit(
              address layer2,
              address account,
              uint256 amount
            ) external checkRound {
              require(msg.sender == _seigManager);
              _increaseEffectiveBalance(account, amount);
              _totalDeposits = _totalDeposits.add(amount);
          
              emit PowerIncreased(account, amount);
            }
          
            function onWithdraw(
              address layer2,
              address account,
              uint256 amount
            ) external checkRound {
              require(msg.sender == _seigManager);
              uint256 v = _decreaseEffectiveBalance(account, amount);
              _totalDeposits = _totalDeposits.sub(v);
              emit PowerDecreased(account, v);
            }
          
            //////////////////////////////
            // External storage getters
            //////////////////////////////
          
            function seigManager() external view returns (address) { return _seigManager; }
            function wton() external view returns (address) { return _wton; }
            function currentRound() external view returns (uint256) { return _currentRound; }
            function roundDuration() external view returns (uint256) { return _roundDuration; }
            function totalDeposits() external view returns (uint256) { return _totalDeposits; }
            function winnerOf(uint256 round) external view returns (address) {
              return rounds[round].winner;
            }
          
            //////////////////////////////
            // Internal functions
            //////////////////////////////
          
            // TODO: enable upgradability
            // TODO: use other entrophy source
            // https://github.com/cryptocopycats/awesome-cryptokitties/blob/master/contracts/GeneScience.sol#L111-L133
            function _seed(uint256 _targetBlock) internal view returns (uint256 randomN) {
              uint256 h = uint256(blockhash(_targetBlock));
          
              if (h == 0) {
                _targetBlock = (block.number & maskFirst248Bits) + (_targetBlock & maskLast8Bits);
                if (_targetBlock >= block.number) _targetBlock -= 256;
          
                h = uint256(blockhash(_targetBlock));
              }
          
              randomN = (h + block.number + uint256(blockhash(block.number - 1))) * h * h * _totalDeposits;
            }
          
            function _startRound(uint256 round) internal {
              require(
                round == 0 ||
                (rounds[round - 1].endTime < block.timestamp
                  && rounds[round - 1].winner != address(0))
              );
          
              Round storage r = rounds[round];
              require(r.startTime == 0 && r.endTime == 0 && r.winner == address(0));
          
              uint64 startTime = uint64(block.timestamp);
              uint64 endTime = uint64(block.timestamp + _roundDuration);
              r.startTime = startTime;
              r.endTime = endTime;
          
              emit RoundStart(round, startTime, endTime);
            }
          
            function _increaseEffectiveBalance(address account, uint256 amount) internal {
              bytes32 id = _getID(account);
              uint256 value = sortitionSumTrees.stakeOf(TREE_KEY, id).add(amount);
          
              sortitionSumTrees.set(TREE_KEY, value, id);
            }
          
            function _decreaseEffectiveBalance(address account, uint256 amount) internal returns (uint256) {
              bytes32 id = _getID(account);
          
              uint256 stake = sortitionSumTrees.stakeOf(TREE_KEY, id);
              uint256 value = _sub0(stake, amount);
          
              sortitionSumTrees.set(TREE_KEY, value, id);
              return stake - value;
            }
          
            /**
             * @dev return a - b if a > b, otherwise 0
             */
            function _sub0(uint256 a, uint256 b) internal pure returns (uint256) {
              if (a > b) return a - b;
              return 0;
            }
          
            function _getID(address account) internal pure returns (bytes32) {
              return bytes32(uint256(account));
            }
          
            function _recoverID(bytes32 id) internal pure returns (address) {
              return address(uint160(uint256(id)));
            }
          
            function _getTreeKey(uint256 round) internal pure returns (bytes32 k) {
              require(round < 2 ** 224);
          
              k = bytes32(TREE_KEY_PREFIX);
              assembly {
                k := add(k, round)
              }
            }
          }

          File 7 of 8: Layer2Registry
          // File: openzeppelin-solidity/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-solidity/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 {
                  address msgSender = _msgSender();
                  _owner = msgSender;
                  emit OwnershipTransferred(address(0), msgSender);
              }
          
              /**
               * @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: contracts/Layer2I.sol
          
          pragma solidity ^0.5.12;
          
          interface Layer2I {
            function operator() external view returns (address);
            function isLayer2() external view returns (bool);
            function currentFork() external view returns (uint);
            function lastEpoch(uint forkNumber) external view returns (uint);
            function changeOperator(address _operator) external;
          }
          
          // File: contracts/stake/interfaces/SeigManagerI.sol
          
          pragma solidity ^0.5.12;
          
          
          interface SeigManagerI {
            function registry() external view returns (address);
            function depositManager() external view returns (address);
            function ton() external view returns (address);
            function wton() external view returns (address);
            function powerton() external view returns (address);
            function tot() external view returns (address);
            function coinages(address layer2) external view returns (address);
            function commissionRates(address layer2) external view returns (uint256);
          
            function lastCommitBlock(address layer2) external view returns (uint256);
            function seigPerBlock() external view returns (uint256);
            function lastSeigBlock() external view returns (uint256);
            function pausedBlock() external view returns (uint256);
            function unpausedBlock() external view returns (uint256);
            function DEFAULT_FACTOR() external view returns (uint256);
          
            function deployCoinage(address layer2) external returns (bool);
            function setCommissionRate(address layer2, uint256 commission, bool isCommissionRateNegative) external returns (bool);
          
            function uncomittedStakeOf(address layer2, address account) external view returns (uint256);
            function stakeOf(address layer2, address account) external view returns (uint256);
            function additionalTotBurnAmount(address layer2, address account, uint256 amount) external view returns (uint256 totAmount);
          
            function onTransfer(address sender, address recipient, uint256 amount) external returns (bool);
            function updateSeigniorage() external returns (bool);
            function onDeposit(address layer2, address account, uint256 amount) external returns (bool);
            function onWithdraw(address layer2, address account, uint256 amount) external returns (bool);
          
          }
          
          // File: contracts/stake/interfaces/Layer2RegistryI.sol
          
          pragma solidity ^0.5.12;
          
          
          interface Layer2RegistryI {
            function layer2s(address layer2) external view returns (bool);
          
            function register(address layer2) external returns (bool);
            function numLayer2s() external view returns (uint256);
            function layer2ByIndex(uint256 index) external view returns (address);
          
            function deployCoinage(address layer2, address seigManager) external returns (bool);
            function registerAndDeployCoinage(address layer2, address seigManager) external returns (bool);
            function unregister(address layer2) external returns (bool);
          }
          
          // File: contracts/stake/Layer2Registry.sol
          
          pragma solidity ^0.5.12;
          
          
          
          
          
          
          // TODO: transfer coinages ownership to seig manager
          contract Layer2Registry is Layer2RegistryI, Ownable {
            // check whether the address is layer2 contract or not
            mapping (address => bool) internal _layer2s;
          
            // array-like storages
            // NOTE: unregistered layer2s could exists in that array. so, should check by layer2s(address)
            uint256 internal _numLayer2s;
            mapping (uint256 => address) internal _layer2ByIndex;
          
            modifier onlyOwnerOrOperator(address layer2) {
              require(isOwner() || Layer2I(layer2).operator() == msg.sender, "sender is neither operator nor operator");
              _;
            }
          
            function layer2s(address layer2) external view returns (bool) {
              return _layer2s[layer2];
            }
          
            function numLayer2s() external view returns (uint256) {
              return _numLayer2s;
            }
          
            function layer2ByIndex(uint256 index) external view returns (address) {
              return _layer2ByIndex[index];
            }
          
            function register(address layer2)
              external
              onlyOwnerOrOperator(layer2)
              returns (bool)
            {
              return _register(layer2);
            }
          
            function _register(address layer2) internal returns (bool) {
              require(!_layer2s[layer2]);
              require(Layer2I(layer2).isLayer2());
          
              _layer2s[layer2] = true;
              _layer2ByIndex[_numLayer2s] = layer2;
              _numLayer2s += 1;
          
              return true;
            }
          
            function deployCoinage(
              address layer2,
              address seigManager
            )
              external
              onlyOwnerOrOperator(layer2)
              returns (bool)
            {
              return _deployCoinage(layer2, seigManager);
            }
          
            function _deployCoinage(
              address layer2,
              address seigManager
            )
             internal
             returns (bool)
            {
              return SeigManagerI(seigManager).deployCoinage(layer2);
            }
          
            function registerAndDeployCoinage(
              address layer2,
              address seigManager
            )
              external
              onlyOwnerOrOperator(layer2)
              returns (bool)
            {
              require(_register(layer2));
              require(_deployCoinage(layer2, seigManager));
              return true;
            }
          
            function registerAndDeployCoinageAndSetCommissionRate(
              address layer2,
              address seigManager,
              uint256 commissionRate,
              bool isCommissionRateNegative
            )
              external
              onlyOwnerOrOperator(layer2)
              returns (bool)
            {
              require(_register(layer2));
              require(_deployCoinage(layer2, seigManager));
              require(_setCommissionRate(layer2, seigManager, commissionRate, isCommissionRateNegative));
              return true;
            }
          
            function _setCommissionRate(
              address layer2,
              address seigManager,
              uint256 commissionRate,
              bool isCommissionRateNegative
            )
              internal
              returns (bool)
            {
              return SeigManagerI(seigManager).setCommissionRate(layer2, commissionRate, isCommissionRateNegative);
            }
          
            function unregister(address layer2) external onlyOwner returns (bool) {
              require(_layer2s[layer2]);
          
              _layer2s[layer2] = false;
            }
          }

          File 8 of 8: SeigManager
          pragma solidity ^0.5.12;
          interface SeigManagerI {
            function registry() external view returns (address);
            function depositManager() external view returns (address);
            function ton() external view returns (address);
            function wton() external view returns (address);
            function powerton() external view returns (address);
            function tot() external view returns (address);
            function coinages(address layer2) external view returns (address);
            function commissionRates(address layer2) external view returns (uint256);
            function lastCommitBlock(address layer2) external view returns (uint256);
            function seigPerBlock() external view returns (uint256);
            function lastSeigBlock() external view returns (uint256);
            function pausedBlock() external view returns (uint256);
            function unpausedBlock() external view returns (uint256);
            function DEFAULT_FACTOR() external view returns (uint256);
            function deployCoinage(address layer2) external returns (bool);
            function setCommissionRate(address layer2, uint256 commission, bool isCommissionRateNegative) external returns (bool);
            function uncomittedStakeOf(address layer2, address account) external view returns (uint256);
            function stakeOf(address layer2, address account) external view returns (uint256);
            function additionalTotBurnAmount(address layer2, address account, uint256 amount) external view returns (uint256 totAmount);
            function onTransfer(address sender, address recipient, uint256 amount) external returns (bool);
            function updateSeigniorage() external returns (bool);
            function onDeposit(address layer2, address account, uint256 amount) external returns (bool);
            function onWithdraw(address layer2, address account, uint256 amount) external returns (bool);
          }
          // https://github.com/dapphub/ds-math/blob/de45767/src/math.sol
          /// math.sol -- mixin for inline numerical wizardry
          // This program is free software: you can redistribute it and/or modify
          // it under the terms of the GNU General Public License as published by
          // the Free Software Foundation, either version 3 of the License, or
          // (at your option) any later version.
          // This program is distributed in the hope that it will be useful,
          // but WITHOUT ANY WARRANTY; without even the implied warranty of
          // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
          // GNU General Public License for more details.
          // You should have received a copy of the GNU General Public License
          // along with this program.  If not, see <http://www.gnu.org/licenses/>.
          pragma solidity >0.4.13;
          contract DSMath {
            function add(uint x, uint y) internal pure returns (uint z) {
              require((z = x + y) >= x, "ds-math-add-overflow");
            }
            function sub(uint x, uint y) internal pure returns (uint z) {
              require((z = x - y) <= x, "ds-math-sub-underflow");
            }
            function mul(uint x, uint y) internal pure returns (uint z) {
              require(y == 0 || (z = x * y) / y == x, "ds-math-mul-overflow");
            }
            function min(uint x, uint y) internal pure returns (uint z) {
              return x <= y ? x : y;
            }
            function max(uint x, uint y) internal pure returns (uint z) {
              return x >= y ? x : y;
            }
            function imin(int x, int y) internal pure returns (int z) {
              return x <= y ? x : y;
            }
            function imax(int x, int y) internal pure returns (int z) {
              return x >= y ? x : y;
            }
            uint constant WAD = 10 ** 18;
            uint constant RAY = 10 ** 27;
            function wmul(uint x, uint y) internal pure returns (uint z) {
              z = add(mul(x, y), WAD / 2) / WAD;
            }
            function rmul(uint x, uint y) internal pure returns (uint z) {
              z = add(mul(x, y), RAY / 2) / RAY;
            }
            function wdiv(uint x, uint y) internal pure returns (uint z) {
              z = add(mul(x, WAD), y / 2) / y;
            }
            function rdiv(uint x, uint y) internal pure returns (uint z) {
              z = add(mul(x, RAY), y / 2) / y;
            }
            function wmul2(uint x, uint y) internal pure returns (uint z) {
              z = mul(x, y) / WAD;
            }
            function rmul2(uint x, uint y) internal pure returns (uint z) {
              z = mul(x, y) / RAY;
            }
            function wdiv2(uint x, uint y) internal pure returns (uint z) {
              z = mul(x, WAD) / y;
            }
            function rdiv2(uint x, uint y) internal pure returns (uint z) {
              z = mul(x, RAY) / y;
            }
            // This famous algorithm is called "exponentiation by squaring"
            // and calculates x^n with x as fixed-point and n as regular unsigned.
            //
            // It's O(log n), instead of O(n) for naive repeated multiplication.
            //
            // These facts are why it works:
            //
            //  If n is even, then x^n = (x^2)^(n/2).
            //  If n is odd,  then x^n = x * x^(n-1),
            //   and applying the equation for even x gives
            //  x^n = x * (x^2)^((n-1) / 2).
            //
            //  Also, EVM division is flooring and
            //  floor[(n-1) / 2] = floor[n / 2].
            //
            function wpow(uint x, uint n) internal pure returns (uint z) {
              z = n % 2 != 0 ? x : WAD;
              for (n /= 2; n != 0; n /= 2) {
                x = wmul(x, x);
                if (n % 2 != 0) {
                  z = wmul(z, x);
                }
              }
            }
            function rpow(uint x, uint n) internal pure returns (uint z) {
              z = n % 2 != 0 ? x : RAY;
              for (n /= 2; n != 0; n /= 2) {
                x = rmul(x, x);
                if (n % 2 != 0) {
                  z = rmul(z, x);
                }
              }
            }
          }
          pragma solidity ^0.5.0;
          import "Context.sol";
          /**
           * @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 {
                  address msgSender = _msgSender();
                  _owner = msgSender;
                  emit OwnershipTransferred(address(0), msgSender);
              }
              /**
               * @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;
              }
          }
          pragma solidity ^0.5.0;
          import "Context.sol";
          import "PauserRole.sol";
          /**
           * @dev Contract module which allows children to implement an emergency stop
           * mechanism that can be triggered by an authorized account.
           *
           * This module is used through inheritance. It will make available the
           * modifiers `whenNotPaused` and `whenPaused`, which can be applied to
           * the functions of your contract. Note that they will not be pausable by
           * simply including this module, only once the modifiers are put in place.
           */
          contract Pausable is Context, PauserRole {
              /**
               * @dev Emitted when the pause is triggered by a pauser (`account`).
               */
              event Paused(address account);
              /**
               * @dev Emitted when the pause is lifted by a pauser (`account`).
               */
              event Unpaused(address account);
              bool private _paused;
              /**
               * @dev Initializes the contract in unpaused state. Assigns the Pauser role
               * to the deployer.
               */
              constructor () internal {
                  _paused = false;
              }
              /**
               * @dev Returns true if the contract is paused, and false otherwise.
               */
              function paused() public view returns (bool) {
                  return _paused;
              }
              /**
               * @dev Modifier to make a function callable only when the contract is not paused.
               */
              modifier whenNotPaused() {
                  require(!_paused, "Pausable: paused");
                  _;
              }
              /**
               * @dev Modifier to make a function callable only when the contract is paused.
               */
              modifier whenPaused() {
                  require(_paused, "Pausable: not paused");
                  _;
              }
              /**
               * @dev Called by a pauser to pause, triggers stopped state.
               */
              function pause() public onlyPauser whenNotPaused {
                  _paused = true;
                  emit Paused(_msgSender());
              }
              /**
               * @dev Called by a pauser to unpause, returns to normal state.
               */
              function unpause() public onlyPauser whenPaused {
                  _paused = false;
                  emit Unpaused(_msgSender());
              }
          }
          pragma solidity ^0.5.12;
          import { Ownable } from "Ownable.sol";
          interface MinterRoleRenounceTarget {
            function renounceMinter() external;
          }
          interface PauserRoleRenounceTarget {
            function renouncePauser() external;
          }
          interface OwnableTarget {
            function renounceOwnership() external;
            function transferOwnership(address newOwner) external;
          }
          contract AuthController is Ownable {
            function renounceMinter(address target) public onlyOwner {
              MinterRoleRenounceTarget(target).renounceMinter();
            }
            function renouncePauser(address target) public onlyOwner {
              PauserRoleRenounceTarget(target).renouncePauser();
            }
            function renounceOwnership(address target) public onlyOwner {
              OwnableTarget(target).renounceOwnership();
            }
            function transferOwnership(address target, address newOwner) public onlyOwner {
              OwnableTarget(target).transferOwnership(newOwner);
            }
          }pragma solidity ^0.5.12;
          import "lib/Roles.sol";
          contract ChallengerRole {
            using Roles for Roles.Role;
            event ChallengerAdded(address indexed account);
            event ChallengerRemoved(address indexed account);
            Roles.Role private _challengers;
            constructor () internal {
              _addChallenger(msg.sender);
            }
            modifier onlyChallenger() {
              require(isChallenger(msg.sender));
              _;
            }
            function isChallenger(address account) public view returns (bool) {
              return _challengers.has(account);
            }
            function addChallenger(address account) public onlyChallenger {
              _addChallenger(account);
            }
            function renounceChallenger() public {
              _removeChallenger(msg.sender);
            }
            function _addChallenger(address account) internal {
              _challengers.add(account);
              emit ChallengerAdded(account);
            }
            function _removeChallenger(address account) internal {
              _challengers.remove(account);
              emit ChallengerRemoved(account);
            }
          }
          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;
              }
          }
          pragma solidity ^0.5.0;
          import "Context.sol";
          import "openzeppelin-solidity/Roles.sol";
          contract PauserRole is Context {
              using Roles for Roles.Role;
              event PauserAdded(address indexed account);
              event PauserRemoved(address indexed account);
              Roles.Role private _pausers;
              constructor () internal {
                  _addPauser(_msgSender());
              }
              modifier onlyPauser() {
                  require(isPauser(_msgSender()), "PauserRole: caller does not have the Pauser role");
                  _;
              }
              function isPauser(address account) public view returns (bool) {
                  return _pausers.has(account);
              }
              function addPauser(address account) public onlyPauser {
                  _addPauser(account);
              }
              function renouncePauser() public {
                  _removePauser(_msgSender());
              }
              function _addPauser(address account) internal {
                  _pausers.add(account);
                  emit PauserAdded(account);
              }
              function _removePauser(address account) internal {
                  _pausers.remove(account);
                  emit PauserRemoved(account);
              }
          }
          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;
              }
          }
          pragma solidity ^0.5.0;
          import "ERC20.sol";
          import "MinterRole.sol";
          /**
           * @dev Extension of {ERC20} that adds a set of accounts with the {MinterRole},
           * which have permission to mint (create) new tokens as they see fit.
           *
           * At construction, the deployer of the contract is the only minter.
           */
          contract ERC20Mintable is ERC20, MinterRole {
              /**
               * @dev See {ERC20-_mint}.
               *
               * Requirements:
               *
               * - the caller must have the {MinterRole}.
               */
              function mint(address account, uint256 amount) public onlyMinter returns (bool) {
                  _mint(account, amount);
                  return true;
              }
          }
          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);
              /**
               * @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);
          }
          pragma solidity ^0.5.0;
          import "IERC20.sol";
          import "SafeMath.sol";
          import "Address.sol";
          /**
           * @title SafeERC20
           * @dev Wrappers around ERC20 operations that throw on failure (when the token
           * contract returns false). Tokens that return no value (and instead revert or
           * throw on failure) are also supported, non-reverting calls are assumed to be
           * successful.
           * To use this library you can add a `using SafeERC20 for 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");
                  }
              }
          }
          pragma solidity ^0.5.12;
          interface AutoRefactorCoinageI {
            function factor() external view returns (uint256);
            function setFactor(uint256 factor) external returns (bool);
            function burn(uint256 amount) external;
            function burnFrom(address account, uint256 amount) external;
            function mint(address account, uint256 amount) external returns (bool);
            function totalSupply() external view returns (uint256);
            function balanceOf(address account) external view returns (uint256);
            function addMinter(address account) external;
            function renounceMinter() external;
            function transferOwnership(address newOwner) external;
          }
          pragma solidity ^0.5.12;
          interface CoinageFactoryI {
            function deploy() external returns (address);
          }
          pragma solidity ^0.5.12;
          interface Layer2I {
            function operator() external view returns (address);
            function isLayer2() external view returns (bool);
            function currentFork() external view returns (uint);
            function lastEpoch(uint forkNumber) external view returns (uint);
            function changeOperator(address _operator) external;
          }
          pragma solidity ^0.5.12;
          interface Layer2RegistryI {
            function layer2s(address layer2) external view returns (bool);
            function register(address layer2) external returns (bool);
            function numLayer2s() external view returns (uint256);
            function layer2ByIndex(uint256 index) external view returns (address);
            function deployCoinage(address layer2, address seigManager) external returns (bool);
            function registerAndDeployCoinage(address layer2, address seigManager) external returns (bool);
            function unregister(address layer2) external returns (bool);
          }
          pragma solidity ^0.5.12;
          interface DepositManagerI {
            function owner() external view returns (address);
            function wton() external view returns (address);
            function registry() external view returns (address);
            function seigManager() external view returns (address);
            function accStaked(address layer2, address account) external view returns (uint256 wtonAmount);
            function accStakedLayer2(address layer2) external view returns (uint256 wtonAmount);
            function accStakedAccount(address account) external view returns (uint256 wtonAmount);
            function pendingUnstaked(address layer2, address account) external view returns (uint256 wtonAmount);
            function pendingUnstakedLayer2(address layer2) external view returns (uint256 wtonAmount);
            function pendingUnstakedAccount(address account) external view returns (uint256 wtonAmount);
            function accUnstaked(address layer2, address account) external view returns (uint256 wtonAmount);
            function accUnstakedLayer2(address layer2) external view returns (uint256 wtonAmount);
            function accUnstakedAccount(address account) external view returns (uint256 wtonAmount);
            function withdrawalRequestIndex(address layer2, address account) external view returns (uint256 index);
            function withdrawalRequest(address layer2, address account, uint256 index) external view returns (uint128 withdrawableBlockNumber, uint128 amount, bool processed );
            function WITHDRAWAL_DELAY() external view returns (uint256);
            function setSeigManager(address seigManager) external;
            function deposit(address layer2, uint256 amount) external returns (bool);
            function requestWithdrawal(address layer2, uint256 amount) external returns (bool);
            function processRequest(address layer2) external returns (bool);
            function requestWithdrawalAll(address layer2) external returns (bool);
            function processRequests(address layer2, uint256 n) external returns (bool);
            function numRequests(address layer2, address account) external view returns (uint256);
            function numPendingRequests(address layer2, address account) external view returns (uint256);
            function slash(address layer2, address recipient, uint256 amount) external returns (bool);
          }
          pragma solidity ^0.5.12;
          interface PowerTONI {
            function seigManager() external view returns (address);
            function wton() external view returns (address);
            function currentRound() external view returns (uint256);
            function roundDuration() external view returns (uint256);
            function totalDeposits() external view returns (uint256);
            function winnerOf(uint256 round) external view returns (address);
            function powerOf(address account) external view returns (uint256);
            function init() external;
            function start() external;
            function endRound() external;
            function onDeposit(address layer2, address account, uint256 amount) external;
            function onWithdraw(address layer2, address account, uint256 amount) external;
          }
          // https://github.com/OpenZeppelin/openzeppelin-contracts/blob/67bca85/contracts/access/Roles.sol
          pragma solidity ^0.5.12;
          /**
           * @title Roles
           * @dev Library for managing addresses assigned to a Role.
           */
          library Roles {
            struct Role {
              mapping (address => bool) bearer;
            }
            /**
             * @dev Give an account access to this role.
             */
            function add(Role storage role, address account) internal {
              require(!has(role, account));
              role.bearer[account] = true;
            }
            /**
             * @dev Remove an account's access to this role.
             */
            function remove(Role storage role, address account) internal {
              require(has(role, account));
              role.bearer[account] = false;
            }
            /**
             * @dev Check if an account has this role.
             * @return bool
             */
            function has(Role storage role, address account) internal view returns (bool) {
              require(account != address(0));
              return role.bearer[account];
            }
          }
          pragma solidity ^0.5.0;
          /**
           * @title Roles
           * @dev Library for managing addresses assigned to a Role.
           */
          library Roles {
              struct Role {
                  mapping (address => bool) bearer;
              }
              /**
               * @dev Give an account access to this role.
               */
              function add(Role storage role, address account) internal {
                  require(!has(role, account), "Roles: account already has role");
                  role.bearer[account] = true;
              }
              /**
               * @dev Remove an account's access to this role.
               */
              function remove(Role storage role, address account) internal {
                  require(has(role, account), "Roles: account does not have role");
                  role.bearer[account] = false;
              }
              /**
               * @dev Check if an account has this role.
               * @return bool
               */
              function has(Role storage role, address account) internal view returns (bool) {
                  require(account != address(0), "Roles: account is the zero address");
                  return role.bearer[account];
              }
          }
          pragma solidity ^0.5.0;
          import "Context.sol";
          import "IERC20.sol";
          import "SafeMath.sol";
          /**
           * @dev Implementation of the {IERC20} interface.
           *
           * This implementation is agnostic to the way tokens are created. This means
           * that a supply mechanism has to be added in a derived contract using {_mint}.
           * For a generic mechanism see {ERC20Mintable}.
           *
           * TIP: For a detailed writeup see our guide
           * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How
           * to implement supply mechanisms].
           *
           * We have followed general OpenZeppelin guidelines: functions revert instead
           * of returning `false` on failure. This behavior is nonetheless conventional
           * and does not conflict with the expectations of ERC20 applications.
           *
           * Additionally, an {Approval} event is emitted on calls to {transferFrom}.
           * This allows applications to reconstruct the allowance for all accounts just
           * by listening to said events. Other implementations of the EIP may not emit
           * these events, as it isn't required by the specification.
           *
           * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}
           * functions have been added to mitigate the well-known issues around setting
           * allowances. See {IERC20-approve}.
           */
          contract ERC20 is Context, IERC20 {
              using SafeMath for uint256;
              mapping (address => uint256) private _balances;
              mapping (address => mapping (address => uint256)) private _allowances;
              uint256 private _totalSupply;
              /**
               * @dev See {IERC20-totalSupply}.
               */
              function totalSupply() public view returns (uint256) {
                  return _totalSupply;
              }
              /**
               * @dev See {IERC20-balanceOf}.
               */
              function balanceOf(address account) public view returns (uint256) {
                  return _balances[account];
              }
              /**
               * @dev See {IERC20-transfer}.
               *
               * Requirements:
               *
               * - `recipient` cannot be the zero address.
               * - the caller must have a balance of at least `amount`.
               */
              function transfer(address recipient, uint256 amount) public returns (bool) {
                  _transfer(_msgSender(), recipient, amount);
                  return true;
              }
              /**
               * @dev See {IERC20-allowance}.
               */
              function allowance(address owner, address spender) public view returns (uint256) {
                  return _allowances[owner][spender];
              }
              /**
               * @dev See {IERC20-approve}.
               *
               * Requirements:
               *
               * - `spender` cannot be the zero address.
               */
              function approve(address spender, uint256 amount) public returns (bool) {
                  _approve(_msgSender(), spender, amount);
                  return true;
              }
              /**
               * @dev See {IERC20-transferFrom}.
               *
               * Emits an {Approval} event indicating the updated allowance. This is not
               * required by the EIP. See the note at the beginning of {ERC20};
               *
               * Requirements:
               * - `sender` and `recipient` cannot be the zero address.
               * - `sender` must have a balance of at least `amount`.
               * - the caller must have allowance for `sender`'s tokens of at least
               * `amount`.
               */
              function transferFrom(address sender, address recipient, uint256 amount) public returns (bool) {
                  _transfer(sender, recipient, amount);
                  _approve(sender, _msgSender(), _allowances[sender][_msgSender()].sub(amount, "ERC20: transfer amount exceeds allowance"));
                  return true;
              }
              /**
               * @dev Atomically increases the allowance granted to `spender` by the caller.
               *
               * This is an alternative to {approve} that can be used as a mitigation for
               * problems described in {IERC20-approve}.
               *
               * Emits an {Approval} event indicating the updated allowance.
               *
               * Requirements:
               *
               * - `spender` cannot be the zero address.
               */
              function increaseAllowance(address spender, uint256 addedValue) public returns (bool) {
                  _approve(_msgSender(), spender, _allowances[_msgSender()][spender].add(addedValue));
                  return true;
              }
              /**
               * @dev Atomically decreases the allowance granted to `spender` by the caller.
               *
               * This is an alternative to {approve} that can be used as a mitigation for
               * problems described in {IERC20-approve}.
               *
               * Emits an {Approval} event indicating the updated allowance.
               *
               * Requirements:
               *
               * - `spender` cannot be the zero address.
               * - `spender` must have allowance for the caller of at least
               * `subtractedValue`.
               */
              function decreaseAllowance(address spender, uint256 subtractedValue) public returns (bool) {
                  _approve(_msgSender(), spender, _allowances[_msgSender()][spender].sub(subtractedValue, "ERC20: decreased allowance below zero"));
                  return true;
              }
              /**
               * @dev Moves tokens `amount` from `sender` to `recipient`.
               *
               * This is internal function is equivalent to {transfer}, and can be used to
               * e.g. implement automatic token fees, slashing mechanisms, etc.
               *
               * Emits a {Transfer} event.
               *
               * Requirements:
               *
               * - `sender` cannot be the zero address.
               * - `recipient` cannot be the zero address.
               * - `sender` must have a balance of at least `amount`.
               */
              function _transfer(address sender, address recipient, uint256 amount) internal {
                  require(sender != address(0), "ERC20: transfer from the zero address");
                  require(recipient != address(0), "ERC20: transfer to the zero address");
                  _balances[sender] = _balances[sender].sub(amount, "ERC20: transfer amount exceeds balance");
                  _balances[recipient] = _balances[recipient].add(amount);
                  emit Transfer(sender, recipient, amount);
              }
              /** @dev Creates `amount` tokens and assigns them to `account`, increasing
               * the total supply.
               *
               * Emits a {Transfer} event with `from` set to the zero address.
               *
               * Requirements
               *
               * - `to` cannot be the zero address.
               */
              function _mint(address account, uint256 amount) internal {
                  require(account != address(0), "ERC20: mint to the zero address");
                  _totalSupply = _totalSupply.add(amount);
                  _balances[account] = _balances[account].add(amount);
                  emit Transfer(address(0), account, amount);
              }
              /**
               * @dev Destroys `amount` tokens from `account`, reducing the
               * total supply.
               *
               * Emits a {Transfer} event with `to` set to the zero address.
               *
               * Requirements
               *
               * - `account` cannot be the zero address.
               * - `account` must have at least `amount` tokens.
               */
              function _burn(address account, uint256 amount) internal {
                  require(account != address(0), "ERC20: burn from the zero address");
                  _balances[account] = _balances[account].sub(amount, "ERC20: burn amount exceeds balance");
                  _totalSupply = _totalSupply.sub(amount);
                  emit Transfer(account, address(0), amount);
              }
              /**
               * @dev Sets `amount` as the allowance of `spender` over the `owner`s tokens.
               *
               * This is internal function is equivalent to `approve`, and can be used to
               * e.g. set automatic allowances for certain subsystems, etc.
               *
               * Emits an {Approval} event.
               *
               * Requirements:
               *
               * - `owner` cannot be the zero address.
               * - `spender` cannot be the zero address.
               */
              function _approve(address owner, address spender, uint256 amount) internal {
                  require(owner != address(0), "ERC20: approve from the zero address");
                  require(spender != address(0), "ERC20: approve to the zero address");
                  _allowances[owner][spender] = amount;
                  emit Approval(owner, spender, amount);
              }
              /**
               * @dev Destroys `amount` tokens from `account`.`amount` is then deducted
               * from the caller's allowance.
               *
               * See {_burn} and {_approve}.
               */
              function _burnFrom(address account, uint256 amount) internal {
                  _burn(account, amount);
                  _approve(account, _msgSender(), _allowances[account][_msgSender()].sub(amount, "ERC20: burn amount exceeds allowance"));
              }
          }
          pragma solidity ^0.5.0;
          import "Context.sol";
          import "openzeppelin-solidity/Roles.sol";
          contract MinterRole is Context {
              using Roles for Roles.Role;
              event MinterAdded(address indexed account);
              event MinterRemoved(address indexed account);
              Roles.Role private _minters;
              constructor () internal {
                  _addMinter(_msgSender());
              }
              modifier onlyMinter() {
                  require(isMinter(_msgSender()), "MinterRole: caller does not have the Minter role");
                  _;
              }
              function isMinter(address account) public view returns (bool) {
                  return _minters.has(account);
              }
              function addMinter(address account) public onlyMinter {
                  _addMinter(account);
              }
              function renounceMinter() public {
                  _removeMinter(_msgSender());
              }
              function _addMinter(address account) internal {
                  _minters.add(account);
                  emit MinterAdded(account);
              }
              function _removeMinter(address account) internal {
                  _minters.remove(account);
                  emit MinterRemoved(account);
              }
          }
          // https://github.com/OpenZeppelin/openzeppelin-solidity/blob/master/contracts/utils/Address.sol
          pragma solidity ^0.5.12;
          /**
           * Utility library of inline functions on addresses
           */
          library Address {
            /**
             * Returns whether the target address is a contract
             * @dev This function will return false if invoked during the constructor of a contract,
             * as the code is not actually created until after the constructor finishes.
             * @param account address of the account to check
             * @return whether the target address is a contract
             */
            function isContract(address account) internal view returns (bool) {
              uint256 size;
              // XXX Currently there is no better way to check if there is a contract in an address
              // than to check the size of the code at that address.
              // See https://ethereum.stackexchange.com/a/14016/36603
              // for more details about how this works.
              // TODO Check this again before the Serenity release, because all addresses will be
              // contracts then.
              // solium-disable-next-line security/no-inline-assembly
              assembly { size := extcodesize(account) }
              return size > 0;
            }
          }
          pragma solidity ^0.5.12;
          import { Ownable } from "Ownable.sol";
          import { Pausable } from "Pausable.sol";
          import { SafeMath } from "SafeMath.sol";
          import { ERC20Mintable } from "ERC20Mintable.sol";
          import { IERC20 } from "IERC20.sol";
          import { SafeERC20 } from "SafeERC20.sol";
          import { DSMath } from "DSMath.sol";
          import { AutoRefactorCoinageI } from "AutoRefactorCoinageI.sol";
          import { CoinageFactoryI } from "CoinageFactoryI.sol";
          import { AuthController } from "AuthController.sol";
          import { ChallengerRole } from "ChallengerRole.sol";
          import { Layer2I } from "Layer2I.sol";
          import { SeigManagerI } from "SeigManagerI.sol";
          import { Layer2RegistryI } from "Layer2RegistryI.sol";
          import { DepositManagerI } from "DepositManagerI.sol";
          import { PowerTONI } from "PowerTONI.sol";
          /**
           * @dev SeigManager gives seigniorage to operator and WTON holders.
           * For each commit by operator, operator (or user) will get seigniorage
           * in propotion to the staked (or delegated) amount of WTON.
           *
           * [Tokens]
           * - {tot} tracks total staked or delegated WTON of each Layer2 contract (and depositor?).
           * - {coinages[layer2]} tracks staked or delegated WTON of user or operator to a Layer2 contract.
           *
           * For each commit by operator,
           *  1. increases all layer2's balance of {tot} by (the staked amount of WTON) /
           *     (total supply of TON and WTON) * (num blocks * seigniorage per block).
           *  2. increases all depositors' blanace of {coinages[layer2]} in proportion to the staked amount of WTON,
           *     up to the increased amount in step (1).
           *  3. set the layer2's balance of {committed} as the layer2's {tot} balance.
           *
           * For each stake or delegate with amount of {v} to a Layer2,
           *  1. mint {v} {coinages[layer2]} tokens to the account
           *  2. mint {v} {tot} tokens to the layer2 contract
           *
           * For each unstake or undelegate (or get rewards) with amount of {v} to a Layer2,
           *  1. burn {v} {coinages[layer2]} tokens from the account
           *  2. burn {v + ⍺} {tot} tokens from the layer2 contract,
           *   where ⍺ = SEIGS * staked ratio of the layer2 * withdrawal ratio of the account
           *     - SEIGS                              = tot total supply - tot total supply at last commit from the layer2
           *     - staked ratio of the layer2     = tot balance of the layer2 / tot total supply
           *     - withdrawal ratio of the account  = amount to withdraw / total supply of coinage
           *
           */
          contract SeigManager is SeigManagerI, DSMath, Ownable, Pausable, AuthController, ChallengerRole {
            using SafeMath for uint256;
            using SafeERC20 for ERC20Mintable;
            //////////////////////////////
            // Common contracts
            //////////////////////////////
            Layer2RegistryI internal _registry;
            DepositManagerI internal _depositManager;
            PowerTONI internal _powerton;
            address public dao;
            //////////////////////////////
            // Token-related
            //////////////////////////////
            // TON token contract
            IERC20 internal _ton;
            // WTON token contract
            ERC20Mintable internal _wton; // TODO: use mintable erc20!
            // contract factory
            CoinageFactoryI public factory;
            // track total deposits of each layer2.
            AutoRefactorCoinageI internal _tot;
            // coinage token for each layer2.
            mapping (address => AutoRefactorCoinageI) internal _coinages;
            // last commit block number for each layer2.
            mapping (address => uint256) internal _lastCommitBlock;
            // total seigniorage per block
            uint256 internal _seigPerBlock;
            // the block number when seigniorages are given
            uint256 internal _lastSeigBlock;
            // block number when paused or unpaused
            uint256 internal _pausedBlock;
            uint256 internal _unpausedBlock;
            // commission rates in RAY
            mapping (address => uint256) internal _commissionRates;
            // whether commission is negative or not (default=possitive)
            mapping (address => bool) internal _isCommissionRateNegative;
            // setting commissionrate delay
            uint256 public adjustCommissionDelay;
            mapping (address => uint256) public delayedCommissionBlock;
            mapping (address => uint256) public delayedCommissionRate;
            mapping (address => bool) public delayedCommissionRateNegative;
            // minimum deposit amount
            uint256 public minimumAmount;
            uint256 public powerTONSeigRate;
            uint256 public daoSeigRate;
            uint256 public relativeSeigRate;
            uint256 public accRelativeSeig;
            //////////////////////////////
            // Constants
            //////////////////////////////
            uint256 constant public RAY = 10 ** 27; // 1 RAY
            uint256 constant internal _DEFAULT_FACTOR = RAY;
            uint256 constant public MAX_VALID_COMMISSION = RAY; // 1 RAY
            uint256 constant public MIN_VALID_COMMISSION = 10 ** 25; // 0.01 RAY
            //////////////////////////////
            // Modifiers
            //////////////////////////////
            modifier onlyRegistry() {
              require(msg.sender == address(_registry));
              _;
            }
            modifier onlyRegistryOrOperator(address layer2) {
              require(msg.sender == address(_registry) || msg.sender == Layer2I(layer2).operator());
              _;
            }
            modifier onlyDepositManager() {
              require(msg.sender == address(_depositManager));
              _;
            }
            modifier onlyLayer2(address layer2) {
              require(_registry.layer2s(layer2));
              _;
            }
            modifier checkCoinage(address layer2) {
              require(address(_coinages[layer2]) != address(0), "SeigManager: coinage has not been deployed yet");
              _;
            }
            //////////////////////////////
            // Events
            //////////////////////////////
            event CoinageCreated(address indexed layer2, address coinage);
            event SeigGiven(address indexed layer2, uint256 totalSeig, uint256 stakedSeig, uint256 unstakedSeig, uint256 powertonSeig, uint256 pseig);
            event Comitted(address indexed layer2);
            event CommissionRateSet(address indexed layer2, uint256 previousRate, uint256 newRate);
            //////////////////////////////
            // Constuctor
            //////////////////////////////
            constructor (
              ERC20Mintable ton,
              ERC20Mintable wton,
              Layer2RegistryI registry,
              DepositManagerI depositManager,
              uint256 seigPerBlock,
              address factory_
            ) public {
              _ton = ton;
              _wton = wton;
              _registry = registry;
              _depositManager = depositManager;
              _seigPerBlock = seigPerBlock;
              factory = CoinageFactoryI(factory_);
              address c = factory.deploy();
              _tot = AutoRefactorCoinageI(c);
              _lastSeigBlock = block.number;
            }
            //////////////////////////////
            // Override Pausable
            //////////////////////////////
            function pause() public onlyPauser whenNotPaused {
              _pausedBlock = block.number;
              super.pause();
            }
            /**
             * @dev Called by a pauser to unpause, returns to normal state.
             */
            function unpause() public onlyPauser whenPaused {
              _unpausedBlock = block.number;
              super.unpause();
            }
            //////////////////////////////
            // External functions
            //////////////////////////////
            /**
             * @dev set PowerTON contract, only by owner.
             */
            function setPowerTON(PowerTONI powerton) external onlyOwner {
              _powerton = powerton;
            }
            function setDao(address daoAddress) external onlyOwner {
              dao = daoAddress;
            }
            /**
             * @dev deploy coinage token for the layer2.
             */
            function deployCoinage(address layer2) external onlyRegistry returns (bool) {
              // create new coinage token for the layer2 contract
              if (address(_coinages[layer2]) == address(0)) {
                address c = factory.deploy();
                _lastCommitBlock[layer2] = block.number;
                addChallenger(layer2);
                _coinages[layer2] = AutoRefactorCoinageI(c);
                emit CoinageCreated(layer2, c);
              }
              return true;
            }
            function setCommissionRate(
              address layer2,
              uint256 commissionRate,
              bool isCommissionRateNegative
            )
              external
              onlyRegistryOrOperator(layer2)
              returns (bool)
            {
              // check commission range
              require(
                (commissionRate == 0) ||
                (MIN_VALID_COMMISSION <= commissionRate && commissionRate <= MAX_VALID_COMMISSION),
                "SeigManager: commission rate must be 0 or between 1 RAY and 0.01 RAY"
              );
              uint256 previous = _commissionRates[layer2];
              if (adjustCommissionDelay == 0) {
                _commissionRates[layer2] = commissionRate;
                _isCommissionRateNegative[layer2] = isCommissionRateNegative;
              } else {
                delayedCommissionBlock[layer2] = block.number + adjustCommissionDelay;
                delayedCommissionRate[layer2] = commissionRate;
                delayedCommissionRateNegative[layer2] = isCommissionRateNegative;
              }
              emit CommissionRateSet(layer2, previous, commissionRate);
              return true;
            }
            function getOperatorAmount(address layer2) public view returns (uint256) {
              address operator = Layer2I(msg.sender).operator();
              return _coinages[layer2].balanceOf(operator);
            }
            /**
             * @dev Callback for a new commit
             */
            function updateSeigniorage()
              external
              checkCoinage(msg.sender)
              returns (bool)
            {
              // short circuit if paused
              if (paused()) {
                return true;
              }
              uint256 operatorAmount = getOperatorAmount(msg.sender);
              require(operatorAmount >= minimumAmount);
              _increaseTot();
              _lastCommitBlock[msg.sender] = block.number;
              // 2. increase total supply of {coinages[layer2]}
              AutoRefactorCoinageI coinage = _coinages[msg.sender];
              uint256 prevTotalSupply = coinage.totalSupply();
              uint256 nextTotalSupply = _tot.balanceOf(msg.sender);
              // short circuit if there is no seigs for the layer2
              if (prevTotalSupply >= nextTotalSupply) {
                emit Comitted(msg.sender);
                return true;
              }
              uint256 seigs = nextTotalSupply - prevTotalSupply;
              address operator = Layer2I(msg.sender).operator();
              uint256 operatorSeigs;
              // calculate commission amount
              bool isCommissionRateNegative = _isCommissionRateNegative[msg.sender];
              (nextTotalSupply, operatorSeigs) = _calcSeigsDistribution(
                msg.sender,
                coinage,
                prevTotalSupply,
                seigs,
                isCommissionRateNegative,
                operator
              );
              // gives seigniorages to the layer2 as coinage
              coinage.setFactor(
                _calcNewFactor(
                  prevTotalSupply,
                  nextTotalSupply,
                  coinage.factor()
                )
              );
              // give commission to operator or delegators
              if (operatorSeigs != 0) {
                if (isCommissionRateNegative) {
                  // TODO: adjust arithmetic error
                  // burn by ?
                  coinage.burnFrom(operator, operatorSeigs);
                } else {
                  coinage.mint(operator, operatorSeigs);
                }
              }
              _wton.mint(address(_depositManager), seigs);
              emit Comitted(msg.sender);
              return true;
            }
            function _calcSeigsDistribution(
              address layer2,
              AutoRefactorCoinageI coinage,
              uint256 prevTotalSupply,
              uint256 seigs,
              bool isCommissionRateNegative,
              address operator
            ) internal returns (
              uint256 nextTotalSupply,
              uint256 operatorSeigs
            ) {
              if (block.number >= delayedCommissionBlock[layer2] && delayedCommissionBlock[layer2] != 0) {
                _commissionRates[layer2] = delayedCommissionRate[layer2];
                _isCommissionRateNegative[layer2] = delayedCommissionRateNegative[layer2];
                delayedCommissionBlock[layer2] = 0;
              }
              uint256 commissionRate = _commissionRates[msg.sender];
              nextTotalSupply = prevTotalSupply + seigs;
              // short circuit if there is no commission rate
              if (commissionRate == 0) {
                return (nextTotalSupply, operatorSeigs);
              }
              // if commission rate is possitive
              if (!isCommissionRateNegative) {
                operatorSeigs = rmul(seigs, commissionRate); // additional seig for operator
                nextTotalSupply = nextTotalSupply.sub(operatorSeigs);
                return (nextTotalSupply, operatorSeigs);
              }
              // short circuit if there is no previous total deposit (meanning, there is no deposit)
              if (prevTotalSupply == 0) {
                return (nextTotalSupply, operatorSeigs);
              }
              // See negative commission distribution formular here: TBD
              uint256 operatorBalance = coinage.balanceOf(operator);
              // short circuit if there is no operator deposit
              if (operatorBalance == 0) {
                return (nextTotalSupply, operatorSeigs);
              }
              uint256 operatorRate = rdiv(operatorBalance, prevTotalSupply);
              // ɑ: insufficient seig for operator
              operatorSeigs = rmul(
                rmul(seigs, operatorRate), // seigs for operator
                commissionRate
              );
              // β:
              uint256 delegatorSeigs = operatorRate == RAY
                ? operatorSeigs
                : rdiv(operatorSeigs, RAY - operatorRate);
              // ?:
              operatorSeigs = operatorRate == RAY
                ? operatorSeigs
                : operatorSeigs + rmul(delegatorSeigs, operatorRate);
              nextTotalSupply = nextTotalSupply.add(delegatorSeigs);
              return (nextTotalSupply, operatorSeigs);
            }
            /**
             * @dev Callback for a token transfer
             */
            function onTransfer(address sender, address recipient, uint256 amount) external returns (bool) {
              require(msg.sender == address(_ton) || msg.sender == address(_wton),
                "SeigManager: only TON or WTON can call onTransfer");
              if (!paused()) {
                _increaseTot();
              }
              return true;
            }
            /**
             * @dev Callback for a new deposit
             */
            function onDeposit(address layer2, address account, uint256 amount)
              external
              onlyDepositManager
              checkCoinage(layer2)
              returns (bool)
            {
              if (_isOperator(layer2, account)) {
                uint256 newAmount = _coinages[layer2].balanceOf(account).add(amount);
                require(newAmount >= minimumAmount, "minimum amount is required");
              }
              _tot.mint(layer2, amount);
              _coinages[layer2].mint(account, amount);
              if (address(_powerton) != address(0)) {
                _powerton.onDeposit(layer2, account, amount);
              }
              return true;
            }
            // DEV ONLY
            event UnstakeLog(uint coinageBurnAmount, uint totBurnAmount);
            function onWithdraw(address layer2, address account, uint256 amount)
              external
              onlyDepositManager
              checkCoinage(layer2)
              returns (bool)
            {
              require(_coinages[layer2].balanceOf(account) >= amount, "SeigManager: insufficiant balance to unstake");
              if (_isOperator(layer2, account)) {
                uint256 newAmount = _coinages[layer2].balanceOf(account).sub(amount);
                require(newAmount >= minimumAmount, "minimum amount is required");
              }
              // burn {v + ⍺} {tot} tokens to the layer2 contract,
              uint256 totAmount = _additionalTotBurnAmount(layer2, account, amount);
              _tot.burnFrom(layer2, amount.add(totAmount));
              // burn {v} {coinages[layer2]} tokens to the account
              _coinages[layer2].burnFrom(account, amount);
              if (address(_powerton) != address(0)) {
                _powerton.onWithdraw(layer2, account, amount);
              }
              emit UnstakeLog(amount, totAmount);
              return true;
            }
            function setPowerTONSeigRate(uint256 powerTONSeigRate_) external onlyOwner {
              require(powerTONSeigRate_ > 0 && powerTONSeigRate_ < RAY, "exceeded seigniorage rate");
              powerTONSeigRate = powerTONSeigRate_;
            }
            function setDaoSeigRate(uint256 daoSeigRate_) external onlyOwner {
              require(daoSeigRate_ > 0 && daoSeigRate_ < RAY, "exceeded seigniorage rate");
              daoSeigRate = daoSeigRate_;
            }
            function setPseigRate(uint256 PseigRate_) external onlyOwner {
              require(PseigRate_ > 0 && PseigRate_ < RAY, "exceeded seigniorage rate");
              relativeSeigRate = PseigRate_;
            }
            function setCoinageFactory(address factory_) external onlyOwner {
              factory = CoinageFactoryI(factory_);
            }
            function addChallenger(address account) public onlyRegistry {
              _addChallenger(account);
            }
            function transferCoinageOwnership(address newSeigManager, address[] calldata coinages) external onlyOwner {
              for (uint256 i = 0; i < coinages.length; i++) {
                AutoRefactorCoinageI c = AutoRefactorCoinageI(coinages[i]);
                c.addMinter(newSeigManager);
                c.renounceMinter();
                c.transferOwnership(newSeigManager);
              }
            }
            function renounceWTONMinter() external onlyOwner {
              _wton.renounceMinter();
            }
            function slash(address layer2, address challenger) external onlyChallenger checkCoinage(layer2) returns (bool) {
              Layer2I(layer2).changeOperator(challenger);
              return true;
            }
            function additionalTotBurnAmount(address layer2, address account, uint256 amount)
              external
              view
              returns (uint256 totAmount)
            {
              return _additionalTotBurnAmount(layer2, account, amount);
            }
            // return ⍺, where ⍺ = (tot.balanceOf(layer2) - coinages[layer2].totalSupply()) * (amount / coinages[layer2].totalSupply())
            function _additionalTotBurnAmount(address layer2, address account, uint256 amount)
              internal
              view
              returns (uint256 totAmount)
            {
              uint256 coinageTotalSupply = _coinages[layer2].totalSupply();
              uint256 totBalalnce = _tot.balanceOf(layer2);
              // NOTE: arithamtic operations (mul and div) make some errors, so we gonna adjust them under 1e-9 WTON.
              //       note that coinageTotalSupply and totBalalnce are RAY values.
              if (coinageTotalSupply > totBalalnce && coinageTotalSupply - totBalalnce < WAD) {
                return 0;
              }
              return rdiv(
                rmul(
                  totBalalnce.sub(coinageTotalSupply),
                  amount
                ),
                coinageTotalSupply
              );
            }
            function setAdjustDelay(uint256 adjustDelay_) external onlyOwner {
              adjustCommissionDelay = adjustDelay_;
            }
            function setMinimumAmount(uint256 minimumAmount_) external onlyOwner {
              minimumAmount = minimumAmount_;
            }
            //////////////////////////////
            // Public and internal functions
            //////////////////////////////
            function uncomittedStakeOf(address layer2, address account) external view returns (uint256) {
              AutoRefactorCoinageI coinage = _coinages[layer2];
              uint256 prevFactor = coinage.factor();
              uint256 prevTotalSupply = coinage.totalSupply();
              uint256 nextTotalSupply = _tot.balanceOf(layer2);
              uint256 newFactor = _calcNewFactor(prevTotalSupply, nextTotalSupply, prevFactor);
              uint256 uncomittedBalance = rmul(
                rdiv(coinage.balanceOf(account), prevFactor),
                newFactor
              );
              return uncomittedBalance
                .sub(_coinages[layer2].balanceOf(account));
            }
            function stakeOf(address layer2, address account) external view returns (uint256) {
              return _coinages[layer2].balanceOf(account);
            }
            function _calcNewFactor(uint256 source, uint256 target, uint256 oldFactor) internal pure returns (uint256) {
              return rdiv(rmul(target, oldFactor), source);
            }
            // DEV ONLY
            event CommitLog1(uint256 totalStakedAmount, uint256 totalSupplyOfWTON, uint256 prevTotalSupply, uint256 nextTotalSupply);
            function _increaseTot() internal returns (bool) {
              // short circuit if already seigniorage is given.
              if (block.number == _lastSeigBlock) {
                return false;
              }
              if (_tot.totalSupply() == 0) {
                _lastSeigBlock = block.number;
                return false;
              }
              uint256 prevTotalSupply;
              uint256 nextTotalSupply;
              // 1. increase total supply of {tot} by maximum seigniorages * staked rate
              //    staked rate = total staked amount / total supply of (W)TON
              prevTotalSupply = _tot.totalSupply();
              // maximum seigniorages
              uint256 maxSeig = _calcNumSeigBlocks().mul(_seigPerBlock);
              // total supply of (W)TON
              uint256 tos = _ton.totalSupply()
                .sub(_ton.balanceOf(address(_wton)))
                .mul(10 ** 9)                                       // convert TON total supply into ray
                .add(_tot.totalSupply());  // consider additional TOT balance as total supply
              // maximum seigniorages * staked rate
              uint256 stakedSeig = rdiv(
                rmul(
                  maxSeig,
                  // total staked amount
                  _tot.totalSupply()
                ),
                tos
              );
              // pseig
              uint256 totalPseig = rmul(maxSeig.sub(stakedSeig), relativeSeigRate);
              nextTotalSupply = prevTotalSupply.add(stakedSeig).add(totalPseig);
              _lastSeigBlock = block.number;
              _tot.setFactor(_calcNewFactor(prevTotalSupply, nextTotalSupply, _tot.factor()));
              // TODO: reduce computation
              // DEV ONLY
              emit CommitLog1(
                _tot.totalSupply(),
                tos,
                prevTotalSupply,
                nextTotalSupply
              );
              uint256 unstakedSeig = maxSeig.sub(stakedSeig);
              uint256 powertonSeig;
              uint256 daoSeig;
              uint256 relativeSeig;
              if (address(_powerton) != address(0)) {
                powertonSeig = rmul(unstakedSeig, powerTONSeigRate);
                _wton.mint(address(_powerton), powertonSeig);
              }
              if (dao != address(0)) {
                daoSeig = rmul(unstakedSeig, daoSeigRate);
                _wton.mint(address(dao), daoSeig);
              }
              if (relativeSeigRate != 0) {
                relativeSeig = totalPseig;
                accRelativeSeig = accRelativeSeig.add(relativeSeig);
              }
              emit SeigGiven(msg.sender, maxSeig, stakedSeig, unstakedSeig, powertonSeig, relativeSeig);
              return true;
            }
            function _calcNumSeigBlocks() internal view returns (uint256) {
              require(!paused());
              uint256 span = block.number - _lastSeigBlock;
              if (_unpausedBlock < _lastSeigBlock) {
                return span;
              }
              return span - (_unpausedBlock - _pausedBlock);
            }
            function _isOperator(address layer2, address operator) internal view returns (bool) {
              return operator == Layer2I(layer2).operator();
            }
            //////////////////////////////
            // Storage getters
            //////////////////////////////
            // solium-disable
            function registry() external view returns (address) { return address(_registry); }
            function depositManager() external view returns (address) { return address(_depositManager); }
            function ton() external view returns (address) { return address(_ton); }
            function wton() external view returns (address) { return address(_wton); }
            function powerton() external view returns (address) { return address(_powerton); }
            function tot() external view returns (address) { return address(_tot); }
            function coinages(address layer2) external view returns (address) { return address(_coinages[layer2]); }
            function commissionRates(address layer2) external view returns (uint256) { return _commissionRates[layer2]; }
            function isCommissionRateNegative(address layer2) external view returns (bool) { return _isCommissionRateNegative[layer2]; }
            function lastCommitBlock(address layer2) external view returns (uint256) { return _lastCommitBlock[layer2]; }
            function seigPerBlock() external view returns (uint256) { return _seigPerBlock; }
            function lastSeigBlock() external view returns (uint256) { return _lastSeigBlock; }
            function pausedBlock() external view returns (uint256) { return _pausedBlock; }
            function unpausedBlock() external view returns (uint256) { return _unpausedBlock; }
            function DEFAULT_FACTOR() external view returns (uint256) { return _DEFAULT_FACTOR; }
            // solium-enable
          }