ETH Price: $2,526.56 (-8.64%)

Transaction Decoder

Block:
10837986 at Sep-11-2020 02:58:04 AM +UTC
Transaction Fee:
0.0063813 ETH $16.12
Gas Used:
42,542 Gas / 150 Gwei

Account State Difference:

  Address   Before After State Difference Code
0x71093650...3d5e0D909
0xE2Bf5fda...78Cf02f3a
4.050543578 Eth
Nonce: 32
4.044162278 Eth
Nonce: 33
0.0063813
(Ethermine)
743.64572447734712482 Eth743.65210577734712482 Eth0.0063813

Execution Trace

SeigManager.setDaoSeigRate( daoSeigRate_=500000000000000000000000000 )
setDaoSeigRate[SeigManager (ln:1471)]
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
}