Transaction Hash:
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 | ||
---|---|---|---|---|---|
0x71093650...3d5e0D909 | |||||
0xE2Bf5fda...78Cf02f3a |
4.050543578 Eth
Nonce: 32
|
4.044162278 Eth
Nonce: 33
| 0.0063813 | ||
0xEA674fdD...16B898ec8
Miner
| (Ethermine) | 743.64572447734712482 Eth | 743.65210577734712482 Eth | 0.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 }