Contract
0xfc00face00000000000000000000000000000000
6
Contract Overview
Fantom: SFC
Balance:
1,458,981,162.476880938293439574 FTM
FTM Value:
$798,646,288.34 (@ $0.55/FTM)
Token:
[ Download CSV Export ]
Latest 25 internal transaction
[ Download CSV Export ]
Contract Name:
SFC
Compiler Version
v0.5.17+commit.d19bba13
Optimization Enabled:
Yes with 10000 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity)
/** *Submitted for verification at FtmScan.com on 2022-04-05 */ pragma solidity ^0.5.0; // SPDX-License-Identifier: GPL-3.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; } } library Decimal { // unit is used for decimals, e.g. 0.123456 function unit() internal pure returns (uint256) { return 1e18; } } contract StakersConstants { using SafeMath for uint256; uint256 internal constant OK_STATUS = 0; uint256 internal constant WITHDRAWN_BIT = 1; uint256 internal constant OFFLINE_BIT = 1 << 3; uint256 internal constant DOUBLESIGN_BIT = 1 << 7; uint256 internal constant CHEATER_MASK = DOUBLESIGN_BIT; /** * @dev Minimum amount of stake for a validator, i.e., 500000 FTM */ function minSelfStake() public pure returns (uint256) { // 500000 FTM return 500000 * 1e18; } /** * @dev Maximum ratio of delegations a validator can have, say, 15 times of self-stake */ function maxDelegatedRatio() public pure returns (uint256) { // 1600% return 16 * Decimal.unit(); } /** * @dev The commission fee in percentage a validator will get from a delegation, e.g., 15% */ function validatorCommission() public pure returns (uint256) { // 15% return (15 * Decimal.unit()) / 100; } /** * @dev The commission fee in percentage a validator will get from a contract, e.g., 30% */ function contractCommission() public pure returns (uint256) { // 30% return (30 * Decimal.unit()) / 100; } /** * @dev The ratio of the reward rate at base rate (no lock), e.g., 30% */ function unlockedRewardRatio() public pure returns (uint256) { // 30% return (30 * Decimal.unit()) / 100; } /** * @dev The minimum duration of a stake/delegation lockup, e.g. 2 weeks */ function minLockupDuration() public pure returns (uint256) { return 86400 * 14; } /** * @dev The maximum duration of a stake/delegation lockup, e.g. 1 year */ function maxLockupDuration() public pure returns (uint256) { return 86400 * 365; } /** * @dev the number of epochs that stake is locked */ function withdrawalPeriodEpochs() public pure returns (uint256) { return 3; } function withdrawalPeriodTime() public pure returns (uint256) { // 7 days return 60 * 60 * 24 * 7; } } /** * @title Initializable * * @dev Helper contract to support initializer functions. To use it, replace * the constructor with a function that has the `initializer` modifier. * WARNING: Unlike constructors, initializer functions must be manually * invoked. This applies both to deploying an Initializable contract, as well * as extending an Initializable contract via inheritance. * WARNING: When used with inheritance, manual care must be taken to not invoke * a parent initializer twice, or ensure that all initializers are idempotent, * because this is not dealt with automatically as with constructors. */ contract Initializable { /** * @dev Indicates that the contract has been initialized. */ bool private initialized; /** * @dev Indicates that the contract is in the process of being initialized. */ bool private initializing; /** * @dev Modifier to use in the initializer function of a contract. */ modifier initializer() { require( initializing || isConstructor() || !initialized, "Contract instance has already been initialized" ); bool isTopLevelCall = !initializing; if (isTopLevelCall) { initializing = true; initialized = true; } _; if (isTopLevelCall) { initializing = false; } } /// @dev Returns true if and only if the function is running in the constructor function isConstructor() private view returns (bool) { // extcodesize checks the size of the code stored in an address, and // address returns the current address. Since the code is still not // deployed when running a constructor, any checks on its code size will // yield zero, making it an effective way to detect if a contract is // under construction or not. address self = address(this); uint256 cs; assembly { cs := extcodesize(self) } return cs == 0; } // Reserved storage space to allow for layout changes in the future. uint256[50] private ______gap; } /** * @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 aplied to your functions to restrict their use to * the owner. */ contract Ownable is Initializable { address private _owner; event OwnershipTransferred( address indexed previousOwner, address indexed newOwner ); /** * @dev Initializes the contract setting the deployer as the initial owner. */ function initialize(address sender) internal initializer { _owner = sender; emit OwnershipTransferred(address(0), _owner); } /** * @dev Returns the address of the current owner. */ function owner() public view returns (address) { return _owner; } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { require(isOwner(), "Ownable: caller is not the owner"); _; } /** * @dev Returns true if the caller is the current owner. */ function isOwner() public view returns (bool) { return msg.sender == _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; } uint256[50] private ______gap; } /** * @dev Version contract gives the versioning information of the implementation contract */ contract Version { /** * @dev Returns the address of the current owner. */ function version() public pure returns (bytes3) { // version 3.0.2 return "302"; } } /** * @dev Interface of the ERC20 standard as defined in the EIP. */ 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 ); } /** * @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 Initializable, 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(msg.sender, 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(msg.sender, 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, msg.sender, _allowances[sender][msg.sender].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( msg.sender, spender, _allowances[msg.sender][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( msg.sender, spender, _allowances[msg.sender][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, msg.sender, _allowances[account][msg.sender].sub( amount, "ERC20: burn amount exceeds allowance" ) ); } uint256[50] private ______gap; } /** * @title Burnable Token * @dev Token that can be irreversibly burned (destroyed). */ contract ERC20Burnable is ERC20 { /** * @dev Burns a specific amount of tokens. * @param value The amount of token to be burned. */ function burn(uint256 value) public { _burn(msg.sender, value); } /** * @dev Burns a specific amount of tokens from the target address and decrements allowance * @param from address The address which you want to send tokens from * @param value uint256 The amount of token to be burned */ function burnFrom(address from, uint256 value) public { _burnFrom(from, value); } /** * @dev Overrides ERC20._burn in order for burn and burnFrom to emit * an additional Burn event. */ function _burn(address who, uint256 value) internal { super._burn(who, value); } } /** * @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(account != address(0)); role.bearer[account] = true; } /** * @dev remove an account's access to this role */ function remove(Role storage role, address account) internal { require(account != address(0)); 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]; } } contract MinterRole { using Roles for Roles.Role; event MinterAdded(address indexed account); event MinterRemoved(address indexed account); Roles.Role private minters; modifier onlyMinter() { require(isMinter(msg.sender)); _; } function isMinter(address account) public view returns (bool) { return minters.has(account); } function renounceMinter() public { minters.remove(msg.sender); } function _removeMinter(address account) internal { minters.remove(account); emit MinterRemoved(account); } function _addMinter(address account) internal { minters.add(account); emit MinterAdded(account); } uint256[50] private ______gap; } /** * @title ERC20Mintable * @dev ERC20 minting logic */ contract ERC20Mintable is ERC20, MinterRole { event MintingFinished(); bool private _mintingFinished = false; modifier onlyBeforeMintingFinished() { require(!_mintingFinished); _; } /** * @return true if the minting is finished. */ function mintingFinished() public view returns (bool) { return _mintingFinished; } /** * @dev Function to mint tokens * @param to The address that will receive the minted tokens. * @param amount The amount of tokens to mint. * @return A boolean that indicates if the operation was successful. */ function mint(address to, uint256 amount) public onlyMinter onlyBeforeMintingFinished returns (bool) { _mint(to, amount); return true; } /** * @dev Function to stop minting new tokens. * @return True if the operation was successful. */ function finishMinting() public onlyMinter onlyBeforeMintingFinished returns (bool) { _mintingFinished = true; emit MintingFinished(); return true; } } contract Spacer { address private _owner; } contract StakeTokenizer is Spacer, Initializable { SFC internal sfc; mapping(address => mapping(uint256 => uint256)) public outstandingSFTM; address public sFTMTokenAddress; function initialize(address _sfc, address _sFTMTokenAddress) public initializer { sfc = SFC(_sfc); sFTMTokenAddress = _sFTMTokenAddress; } function mintSFTM(uint256 toValidatorID) external { address delegator = msg.sender; uint256 lockedStake = sfc.getLockedStake(delegator, toValidatorID); require(lockedStake > 0, "delegation isn't locked up"); require( lockedStake > outstandingSFTM[delegator][toValidatorID], "sFTM is already minted" ); uint256 diff = lockedStake - outstandingSFTM[delegator][toValidatorID]; outstandingSFTM[delegator][toValidatorID] = lockedStake; // It's important that we mint after updating outstandingSFTM (protection against Re-Entrancy) require( ERC20Mintable(sFTMTokenAddress).mint(delegator, diff), "failed to mint sFTM" ); } function redeemSFTM(uint256 validatorID, uint256 amount) external { require( outstandingSFTM[msg.sender][validatorID] >= amount, "low outstanding sFTM balance" ); require( IERC20(sFTMTokenAddress).allowance(msg.sender, address(this)) >= amount, "insufficient allowance" ); outstandingSFTM[msg.sender][validatorID] -= amount; // It's important that we burn after updating outstandingSFTM (protection against Re-Entrancy) ERC20Burnable(sFTMTokenAddress).burnFrom(msg.sender, amount); } function allowedToWithdrawStake(address sender, uint256 validatorID) public view returns (bool) { return outstandingSFTM[sender][validatorID] == 0; } } /** * @dev Stakers contract defines data structure and methods for validators / validators. */ contract SFC is Initializable, Ownable, StakersConstants, Version { using SafeMath for uint256; /** * @dev The staking for validation */ struct Validator { uint256 status; uint256 deactivatedTime; uint256 deactivatedEpoch; uint256 receivedStake; uint256 createdEpoch; uint256 createdTime; address auth; } NodeDriverAuth internal node; uint256 public currentSealedEpoch; mapping(uint256 => Validator) public getValidator; mapping(address => uint256) public getValidatorID; mapping(uint256 => bytes) public getValidatorPubkey; uint256 public lastValidatorID; uint256 public totalStake; uint256 public totalActiveStake; uint256 public totalSlashedStake; struct Rewards { uint256 lockupExtraReward; uint256 lockupBaseReward; uint256 unlockedReward; } mapping(address => mapping(uint256 => Rewards)) internal _rewardsStash; // addr, validatorID -> Rewards mapping(address => mapping(uint256 => uint256)) public stashedRewardsUntilEpoch; struct WithdrawalRequest { uint256 epoch; uint256 time; uint256 amount; } mapping(address => mapping(uint256 => mapping(uint256 => WithdrawalRequest))) public getWithdrawalRequest; struct LockedDelegation { uint256 lockedStake; uint256 fromEpoch; uint256 endTime; uint256 duration; } mapping(address => mapping(uint256 => uint256)) public getStake; mapping(address => mapping(uint256 => LockedDelegation)) public getLockupInfo; mapping(address => mapping(uint256 => Rewards)) public getStashedLockupRewards; struct EpochSnapshot { mapping(uint256 => uint256) receivedStake; mapping(uint256 => uint256) accumulatedRewardPerToken; mapping(uint256 => uint256) accumulatedUptime; mapping(uint256 => uint256) accumulatedOriginatedTxsFee; mapping(uint256 => uint256) offlineTime; mapping(uint256 => uint256) offlineBlocks; uint256[] validatorIDs; uint256 endTime; uint256 epochFee; uint256 totalBaseRewardWeight; uint256 totalTxRewardWeight; uint256 baseRewardPerSecond; uint256 totalStake; uint256 totalSupply; } uint256 public baseRewardPerSecond; uint256 public totalSupply; mapping(uint256 => EpochSnapshot) public getEpochSnapshot; uint256 offlinePenaltyThresholdBlocksNum; uint256 offlinePenaltyThresholdTime; mapping(uint256 => uint256) public slashingRefundRatio; // validator ID -> (slashing refund ratio) address public stakeTokenizerAddress; function isNode(address addr) internal view returns (bool) { return addr == address(node); } modifier onlyDriver() { require( isNode(msg.sender), "caller is not the NodeDriverAuth contract" ); _; } event CreatedValidator( uint256 indexed validatorID, address indexed auth, uint256 createdEpoch, uint256 createdTime ); event DeactivatedValidator( uint256 indexed validatorID, uint256 deactivatedEpoch, uint256 deactivatedTime ); event ChangedValidatorStatus(uint256 indexed validatorID, uint256 status); event Delegated( address indexed delegator, uint256 indexed toValidatorID, uint256 amount ); event Undelegated( address indexed delegator, uint256 indexed toValidatorID, uint256 indexed wrID, uint256 amount ); event Withdrawn( address indexed delegator, uint256 indexed toValidatorID, uint256 indexed wrID, uint256 amount ); event ClaimedRewards( address indexed delegator, uint256 indexed toValidatorID, uint256 lockupExtraReward, uint256 lockupBaseReward, uint256 unlockedReward ); event RestakedRewards( address indexed delegator, uint256 indexed toValidatorID, uint256 lockupExtraReward, uint256 lockupBaseReward, uint256 unlockedReward ); event InflatedFTM( address indexed receiver, uint256 amount, string justification ); event LockedUpStake( address indexed delegator, uint256 indexed validatorID, uint256 duration, uint256 amount ); event UnlockedStake( address indexed delegator, uint256 indexed validatorID, uint256 amount, uint256 penalty ); event UpdatedBaseRewardPerSec(uint256 value); event UpdatedOfflinePenaltyThreshold(uint256 blocksNum, uint256 period); event UpdatedSlashingRefundRatio( uint256 indexed validatorID, uint256 refundRatio ); event RefundedSlashedLegacyDelegation( address indexed delegator, uint256 indexed validatorID, uint256 amount ); /* Getters */ function currentEpoch() public view returns (uint256) { return currentSealedEpoch + 1; } function getEpochValidatorIDs(uint256 epoch) public view returns (uint256[] memory) { return getEpochSnapshot[epoch].validatorIDs; } function getEpochReceivedStake(uint256 epoch, uint256 validatorID) public view returns (uint256) { return getEpochSnapshot[epoch].receivedStake[validatorID]; } function getEpochAccumulatedRewardPerToken( uint256 epoch, uint256 validatorID ) public view returns (uint256) { return getEpochSnapshot[epoch].accumulatedRewardPerToken[validatorID]; } function getEpochAccumulatedUptime(uint256 epoch, uint256 validatorID) public view returns (uint256) { return getEpochSnapshot[epoch].accumulatedUptime[validatorID]; } function getEpochAccumulatedOriginatedTxsFee( uint256 epoch, uint256 validatorID ) public view returns (uint256) { return getEpochSnapshot[epoch].accumulatedOriginatedTxsFee[validatorID]; } function getEpochOfflineTime(uint256 epoch, uint256 validatorID) public view returns (uint256) { return getEpochSnapshot[epoch].offlineTime[validatorID]; } function getEpochOfflineBlocks(uint256 epoch, uint256 validatorID) public view returns (uint256) { return getEpochSnapshot[epoch].offlineBlocks[validatorID]; } function rewardsStash(address delegator, uint256 validatorID) public view returns (uint256) { Rewards memory stash = _rewardsStash[delegator][validatorID]; return stash.lockupBaseReward.add(stash.lockupExtraReward).add( stash.unlockedReward ); } function getLockedStake(address delegator, uint256 toValidatorID) public view returns (uint256) { if (!isLockedUp(delegator, toValidatorID)) { return 0; } return getLockupInfo[delegator][toValidatorID].lockedStake; } /* Constructor */ function initialize( uint256 sealedEpoch, uint256 _totalSupply, address nodeDriver, address owner ) external initializer { Ownable.initialize(owner); currentSealedEpoch = sealedEpoch; node = NodeDriverAuth(nodeDriver); totalSupply = _totalSupply; baseRewardPerSecond = 6.183414351851851852 * 1e18; offlinePenaltyThresholdBlocksNum = 1000; offlinePenaltyThresholdTime = 3 days; getEpochSnapshot[sealedEpoch].endTime = _now(); } function setGenesisValidator( address auth, uint256 validatorID, bytes calldata pubkey, uint256 status, uint256 createdEpoch, uint256 createdTime, uint256 deactivatedEpoch, uint256 deactivatedTime ) external onlyDriver { _rawCreateValidator( auth, validatorID, pubkey, status, createdEpoch, createdTime, deactivatedEpoch, deactivatedTime ); if (validatorID > lastValidatorID) { lastValidatorID = validatorID; } } function setGenesisDelegation( address delegator, uint256 toValidatorID, uint256 stake, uint256 lockedStake, uint256 lockupFromEpoch, uint256 lockupEndTime, uint256 lockupDuration, uint256 earlyUnlockPenalty, uint256 rewards ) external onlyDriver { _rawDelegate(delegator, toValidatorID, stake); _rewardsStash[delegator][toValidatorID].unlockedReward = rewards; _mintNativeToken(stake); if (lockedStake != 0) { require( lockedStake <= stake, "locked stake is greater than the whole stake" ); LockedDelegation storage ld = getLockupInfo[delegator][ toValidatorID ]; ld.lockedStake = lockedStake; ld.fromEpoch = lockupFromEpoch; ld.endTime = lockupEndTime; ld.duration = lockupDuration; getStashedLockupRewards[delegator][toValidatorID] .lockupExtraReward = earlyUnlockPenalty; emit LockedUpStake( delegator, toValidatorID, lockupDuration, lockedStake ); } } /* Methods */ function createValidator(bytes calldata pubkey) external payable { require(msg.value >= minSelfStake(), "insufficient self-stake"); require(pubkey.length > 0, "empty pubkey"); _createValidator(msg.sender, pubkey); _delegate(msg.sender, lastValidatorID, msg.value); } function _createValidator(address auth, bytes memory pubkey) internal { uint256 validatorID = ++lastValidatorID; _rawCreateValidator( auth, validatorID, pubkey, OK_STATUS, currentEpoch(), _now(), 0, 0 ); } function _rawCreateValidator( address auth, uint256 validatorID, bytes memory pubkey, uint256 status, uint256 createdEpoch, uint256 createdTime, uint256 deactivatedEpoch, uint256 deactivatedTime ) internal { require(getValidatorID[auth] == 0, "validator already exists"); getValidatorID[auth] = validatorID; getValidator[validatorID].status = status; getValidator[validatorID].createdEpoch = createdEpoch; getValidator[validatorID].createdTime = createdTime; getValidator[validatorID].deactivatedTime = deactivatedTime; getValidator[validatorID].deactivatedEpoch = deactivatedEpoch; getValidator[validatorID].auth = auth; getValidatorPubkey[validatorID] = pubkey; emit CreatedValidator(validatorID, auth, createdEpoch, createdTime); if (deactivatedEpoch != 0) { emit DeactivatedValidator( validatorID, deactivatedEpoch, deactivatedTime ); } if (status != 0) { emit ChangedValidatorStatus(validatorID, status); } } function getSelfStake(uint256 validatorID) public view returns (uint256) { return getStake[getValidator[validatorID].auth][validatorID]; } function _checkDelegatedStakeLimit(uint256 validatorID) internal view returns (bool) { return getValidator[validatorID].receivedStake <= getSelfStake(validatorID).mul(maxDelegatedRatio()).div( Decimal.unit() ); } function delegate(uint256 toValidatorID) external payable { _delegate(msg.sender, toValidatorID, msg.value); } function _delegate( address delegator, uint256 toValidatorID, uint256 amount ) internal { require(_validatorExists(toValidatorID), "validator doesn't exist"); require( getValidator[toValidatorID].status == OK_STATUS, "validator isn't active" ); _rawDelegate(delegator, toValidatorID, amount); require( _checkDelegatedStakeLimit(toValidatorID), "validator's delegations limit is exceeded" ); } function _rawDelegate( address delegator, uint256 toValidatorID, uint256 amount ) internal { require(amount > 0, "zero amount"); _stashRewards(delegator, toValidatorID); getStake[delegator][toValidatorID] = getStake[delegator][toValidatorID] .add(amount); uint256 origStake = getValidator[toValidatorID].receivedStake; getValidator[toValidatorID].receivedStake = origStake.add(amount); totalStake = totalStake.add(amount); if (getValidator[toValidatorID].status == OK_STATUS) { totalActiveStake = totalActiveStake.add(amount); } _syncValidator(toValidatorID, origStake == 0); emit Delegated(delegator, toValidatorID, amount); } function _setValidatorDeactivated(uint256 validatorID, uint256 status) internal { if ( getValidator[validatorID].status == OK_STATUS && status != OK_STATUS ) { totalActiveStake = totalActiveStake.sub( getValidator[validatorID].receivedStake ); } // status as a number is proportional to severity if (status > getValidator[validatorID].status) { getValidator[validatorID].status = status; if (getValidator[validatorID].deactivatedEpoch == 0) { getValidator[validatorID].deactivatedEpoch = currentEpoch(); getValidator[validatorID].deactivatedTime = _now(); emit DeactivatedValidator( validatorID, getValidator[validatorID].deactivatedEpoch, getValidator[validatorID].deactivatedTime ); } emit ChangedValidatorStatus(validatorID, status); } } function _rawUndelegate( address delegator, uint256 toValidatorID, uint256 amount ) internal { getStake[delegator][toValidatorID] -= amount; getValidator[toValidatorID].receivedStake = getValidator[toValidatorID] .receivedStake .sub(amount); totalStake = totalStake.sub(amount); if (getValidator[toValidatorID].status == OK_STATUS) { totalActiveStake = totalActiveStake.sub(amount); } uint256 selfStakeAfterwards = getSelfStake(toValidatorID); if (selfStakeAfterwards != 0) { require( selfStakeAfterwards >= minSelfStake(), "insufficient self-stake" ); require( _checkDelegatedStakeLimit(toValidatorID), "validator's delegations limit is exceeded" ); } else { _setValidatorDeactivated(toValidatorID, WITHDRAWN_BIT); } } function undelegate( uint256 toValidatorID, uint256 wrID, uint256 amount ) public { address delegator = msg.sender; _stashRewards(delegator, toValidatorID); require(amount > 0, "zero amount"); require( amount <= getUnlockedStake(delegator, toValidatorID), "not enough unlocked stake" ); require( _checkAllowedToWithdraw(delegator, toValidatorID), "outstanding sFTM balance" ); require( getWithdrawalRequest[delegator][toValidatorID][wrID].amount == 0, "wrID already exists" ); _rawUndelegate(delegator, toValidatorID, amount); getWithdrawalRequest[delegator][toValidatorID][wrID].amount = amount; getWithdrawalRequest[delegator][toValidatorID][wrID] .epoch = currentEpoch(); getWithdrawalRequest[delegator][toValidatorID][wrID].time = _now(); _syncValidator(toValidatorID, false); emit Undelegated(delegator, toValidatorID, wrID, amount); } function isSlashed(uint256 validatorID) public view returns (bool) { return getValidator[validatorID].status & CHEATER_MASK != 0; } function getSlashingPenalty( uint256 amount, bool isCheater, uint256 refundRatio ) internal pure returns (uint256 penalty) { if (!isCheater || refundRatio >= Decimal.unit()) { return 0; } // round penalty upwards (ceiling) to prevent dust amount attacks penalty = amount .mul(Decimal.unit() - refundRatio) .div(Decimal.unit()) .add(1); if (penalty > amount) { return amount; } return penalty; } function withdraw(uint256 toValidatorID, uint256 wrID) public { address payable delegator = msg.sender; WithdrawalRequest memory request = getWithdrawalRequest[delegator][ toValidatorID ][wrID]; require(request.epoch != 0, "request doesn't exist"); require( _checkAllowedToWithdraw(delegator, toValidatorID), "outstanding sFTM balance" ); uint256 requestTime = request.time; uint256 requestEpoch = request.epoch; if ( getValidator[toValidatorID].deactivatedTime != 0 && getValidator[toValidatorID].deactivatedTime < requestTime ) { requestTime = getValidator[toValidatorID].deactivatedTime; requestEpoch = getValidator[toValidatorID].deactivatedEpoch; } require( _now() >= requestTime + withdrawalPeriodTime(), "not enough time passed" ); require( currentEpoch() >= requestEpoch + withdrawalPeriodEpochs(), "not enough epochs passed" ); uint256 amount = getWithdrawalRequest[delegator][toValidatorID][wrID] .amount; bool isCheater = isSlashed(toValidatorID); uint256 penalty = getSlashingPenalty( amount, isCheater, slashingRefundRatio[toValidatorID] ); delete getWithdrawalRequest[delegator][toValidatorID][wrID]; totalSlashedStake += penalty; require(amount > penalty, "stake is fully slashed"); // It's important that we transfer after erasing (protection against Re-Entrancy) (bool sent, ) = delegator.call.value(amount.sub(penalty))(""); require(sent, "Failed to send FTM"); emit Withdrawn(delegator, toValidatorID, wrID, amount); } function deactivateValidator(uint256 validatorID, uint256 status) external onlyDriver { require(status != OK_STATUS, "wrong status"); _setValidatorDeactivated(validatorID, status); _syncValidator(validatorID, false); } function _calcRawValidatorEpochBaseReward( uint256 epochDuration, uint256 _baseRewardPerSecond, uint256 baseRewardWeight, uint256 totalBaseRewardWeight ) internal pure returns (uint256) { if (baseRewardWeight == 0) { return 0; } uint256 totalReward = epochDuration.mul(_baseRewardPerSecond); return totalReward.mul(baseRewardWeight).div(totalBaseRewardWeight); } function _calcRawValidatorEpochTxReward( uint256 epochFee, uint256 txRewardWeight, uint256 totalTxRewardWeight ) internal pure returns (uint256) { if (txRewardWeight == 0) { return 0; } uint256 txReward = epochFee.mul(txRewardWeight).div( totalTxRewardWeight ); // fee reward except contractCommission return txReward.mul(Decimal.unit() - contractCommission()).div( Decimal.unit() ); } function _calcValidatorCommission(uint256 rawReward, uint256 commission) internal pure returns (uint256) { return rawReward.mul(commission).div(Decimal.unit()); } function _highestPayableEpoch(uint256 validatorID) internal view returns (uint256) { if (getValidator[validatorID].deactivatedEpoch != 0) { if ( currentSealedEpoch < getValidator[validatorID].deactivatedEpoch ) { return currentSealedEpoch; } return getValidator[validatorID].deactivatedEpoch; } return currentSealedEpoch; } // find highest epoch such that _isLockedUpAtEpoch returns true (using binary search) function _highestLockupEpoch(address delegator, uint256 validatorID) internal view returns (uint256) { uint256 l = getLockupInfo[delegator][validatorID].fromEpoch; uint256 r = currentSealedEpoch; if (_isLockedUpAtEpoch(delegator, validatorID, r)) { return r; } if (!_isLockedUpAtEpoch(delegator, validatorID, l)) { return 0; } if (l > r) { return 0; } while (l < r) { uint256 m = (l + r) / 2; if (_isLockedUpAtEpoch(delegator, validatorID, m)) { l = m + 1; } else { r = m; } } if (r == 0) { return 0; } return r - 1; } function _scaleLockupReward(uint256 fullReward, uint256 lockupDuration) internal pure returns (Rewards memory reward) { reward = Rewards(0, 0, 0); if (lockupDuration != 0) { uint256 maxLockupExtraRatio = Decimal.unit() - unlockedRewardRatio(); uint256 lockupExtraRatio = maxLockupExtraRatio .mul(lockupDuration) .div(maxLockupDuration()); uint256 totalScaledReward = fullReward .mul(unlockedRewardRatio() + lockupExtraRatio) .div(Decimal.unit()); reward.lockupBaseReward = fullReward.mul(unlockedRewardRatio()).div( Decimal.unit() ); reward.lockupExtraReward = totalScaledReward - reward.lockupBaseReward; } else { reward.unlockedReward = fullReward.mul(unlockedRewardRatio()).div( Decimal.unit() ); } return reward; } function sumRewards(Rewards memory a, Rewards memory b) internal pure returns (Rewards memory) { return Rewards( a.lockupExtraReward.add(b.lockupExtraReward), a.lockupBaseReward.add(b.lockupBaseReward), a.unlockedReward.add(b.unlockedReward) ); } function sumRewards( Rewards memory a, Rewards memory b, Rewards memory c ) internal pure returns (Rewards memory) { return sumRewards(sumRewards(a, b), c); } function _newRewards(address delegator, uint256 toValidatorID) internal view returns (Rewards memory) { uint256 stashedUntil = stashedRewardsUntilEpoch[delegator][ toValidatorID ]; uint256 payableUntil = _highestPayableEpoch(toValidatorID); uint256 lockedUntil = _highestLockupEpoch(delegator, toValidatorID); if (lockedUntil > payableUntil) { lockedUntil = payableUntil; } if (lockedUntil < stashedUntil) { lockedUntil = stashedUntil; } LockedDelegation storage ld = getLockupInfo[delegator][toValidatorID]; uint256 wholeStake = getStake[delegator][toValidatorID]; uint256 unlockedStake = wholeStake.sub(ld.lockedStake); uint256 fullReward; // count reward for locked stake during lockup epochs fullReward = _newRewardsOf( ld.lockedStake, toValidatorID, stashedUntil, lockedUntil ); Rewards memory plReward = _scaleLockupReward(fullReward, ld.duration); // count reward for unlocked stake during lockup epochs fullReward = _newRewardsOf( unlockedStake, toValidatorID, stashedUntil, lockedUntil ); Rewards memory puReward = _scaleLockupReward(fullReward, 0); // count lockup reward for unlocked stake during unlocked epochs fullReward = _newRewardsOf( wholeStake, toValidatorID, lockedUntil, payableUntil ); Rewards memory wuReward = _scaleLockupReward(fullReward, 0); return sumRewards(plReward, puReward, wuReward); } function _newRewardsOf( uint256 stakeAmount, uint256 toValidatorID, uint256 fromEpoch, uint256 toEpoch ) internal view returns (uint256) { if (fromEpoch >= toEpoch) { return 0; } uint256 stashedRate = getEpochSnapshot[fromEpoch] .accumulatedRewardPerToken[toValidatorID]; uint256 currentRate = getEpochSnapshot[toEpoch] .accumulatedRewardPerToken[toValidatorID]; return currentRate.sub(stashedRate).mul(stakeAmount).div(Decimal.unit()); } function _pendingRewards(address delegator, uint256 toValidatorID) internal view returns (Rewards memory) { Rewards memory reward = _newRewards(delegator, toValidatorID); return sumRewards(_rewardsStash[delegator][toValidatorID], reward); } function pendingRewards(address delegator, uint256 toValidatorID) public view returns (uint256) { Rewards memory reward = _pendingRewards(delegator, toValidatorID); return reward.unlockedReward.add(reward.lockupBaseReward).add( reward.lockupExtraReward ); } function stashRewards(address delegator, uint256 toValidatorID) external { require(_stashRewards(delegator, toValidatorID), "nothing to stash"); } function _stashRewards(address delegator, uint256 toValidatorID) internal returns (bool updated) { Rewards memory nonStashedReward = _newRewards(delegator, toValidatorID); stashedRewardsUntilEpoch[delegator][ toValidatorID ] = _highestPayableEpoch(toValidatorID); _rewardsStash[delegator][toValidatorID] = sumRewards( _rewardsStash[delegator][toValidatorID], nonStashedReward ); getStashedLockupRewards[delegator][toValidatorID] = sumRewards( getStashedLockupRewards[delegator][toValidatorID], nonStashedReward ); if (!isLockedUp(delegator, toValidatorID)) { delete getLockupInfo[delegator][toValidatorID]; delete getStashedLockupRewards[delegator][toValidatorID]; } return nonStashedReward.lockupBaseReward != 0 || nonStashedReward.lockupExtraReward != 0 || nonStashedReward.unlockedReward != 0; } function _mintNativeToken(uint256 amount) internal { // balance will be increased after the transaction is processed node.incBalance(address(this), amount); totalSupply = totalSupply.add(amount); } function _claimRewards(address delegator, uint256 toValidatorID) internal returns (Rewards memory rewards) { _stashRewards(delegator, toValidatorID); rewards = _rewardsStash[delegator][toValidatorID]; uint256 totalReward = rewards .unlockedReward .add(rewards.lockupBaseReward) .add(rewards.lockupExtraReward); require(totalReward != 0, "zero rewards"); delete _rewardsStash[delegator][toValidatorID]; // It's important that we mint after erasing (protection against Re-Entrancy) _mintNativeToken(totalReward); return rewards; } function claimRewards(uint256 toValidatorID) public { address payable delegator = msg.sender; Rewards memory rewards = _claimRewards(delegator, toValidatorID); // It's important that we transfer after erasing (protection against Re-Entrancy) (bool sent, ) = delegator.call.value( rewards.lockupExtraReward.add(rewards.lockupBaseReward).add( rewards.unlockedReward ) )(""); require(sent, "Failed to send FTM"); emit ClaimedRewards( delegator, toValidatorID, rewards.lockupExtraReward, rewards.lockupBaseReward, rewards.unlockedReward ); } function restakeRewards(uint256 toValidatorID) public { address delegator = msg.sender; Rewards memory rewards = _claimRewards(delegator, toValidatorID); uint256 lockupReward = rewards.lockupExtraReward.add( rewards.lockupBaseReward ); _delegate( delegator, toValidatorID, lockupReward.add(rewards.unlockedReward) ); getLockupInfo[delegator][toValidatorID].lockedStake += lockupReward; emit RestakedRewards( delegator, toValidatorID, rewards.lockupExtraReward, rewards.lockupBaseReward, rewards.unlockedReward ); } // _syncValidator updates the validator data on node function _syncValidator(uint256 validatorID, bool syncPubkey) public { require(_validatorExists(validatorID), "validator doesn't exist"); // emit special log for node uint256 weight = getValidator[validatorID].receivedStake; if (getValidator[validatorID].status != OK_STATUS) { weight = 0; } node.updateValidatorWeight(validatorID, weight); if (syncPubkey && weight != 0) { node.updateValidatorPubkey( validatorID, getValidatorPubkey[validatorID] ); } } function _validatorExists(uint256 validatorID) internal view returns (bool) { return getValidator[validatorID].createdTime != 0; } function offlinePenaltyThreshold() public view returns (uint256 blocksNum, uint256 time) { return (offlinePenaltyThresholdBlocksNum, offlinePenaltyThresholdTime); } function updateBaseRewardPerSecond(uint256 value) external onlyOwner { require( value <= 32.967977168935185184 * 1e18, "too large reward per second" ); baseRewardPerSecond = value; emit UpdatedBaseRewardPerSec(value); } function updateOfflinePenaltyThreshold(uint256 blocksNum, uint256 time) external onlyOwner { offlinePenaltyThresholdTime = time; offlinePenaltyThresholdBlocksNum = blocksNum; emit UpdatedOfflinePenaltyThreshold(blocksNum, time); } function updateSlashingRefundRatio(uint256 validatorID, uint256 refundRatio) external onlyOwner { require(isSlashed(validatorID), "validator isn't slashed"); require( refundRatio <= Decimal.unit(), "must be less than or equal to 1.0" ); slashingRefundRatio[validatorID] = refundRatio; emit UpdatedSlashingRefundRatio(validatorID, refundRatio); } function updateStakeTokenizerAddress(address addr) external onlyOwner { stakeTokenizerAddress = addr; } // updateTotalSupply allows to fix the different between actual total supply and totalSupply field due to the // bug fixed in 3c828b56b7cd32ea058a954fad3cd726e193cc77 function updateTotalSupply(int256 diff) external onlyOwner { if (diff >= 0) { totalSupply += uint256(diff); } else { totalSupply -= uint256(-diff); } } // mintFTM allows SFC owner to mint an arbitrary amount of FTM tokens // justification is a human readable description of why tokens were minted (e.g. because ERC20 FTM tokens were burnt) function mintFTM( address payable receiver, uint256 amount, string calldata justification ) external onlyOwner { _mintNativeToken(amount); receiver.transfer(amount); emit InflatedFTM(receiver, amount, justification); } function _sealEpoch_offline( EpochSnapshot storage snapshot, uint256[] memory validatorIDs, uint256[] memory offlineTime, uint256[] memory offlineBlocks ) internal { // mark offline nodes for (uint256 i = 0; i < validatorIDs.length; i++) { if ( offlineBlocks[i] > offlinePenaltyThresholdBlocksNum && offlineTime[i] >= offlinePenaltyThresholdTime ) { _setValidatorDeactivated(validatorIDs[i], OFFLINE_BIT); _syncValidator(validatorIDs[i], false); } // log data snapshot.offlineTime[validatorIDs[i]] = offlineTime[i]; snapshot.offlineBlocks[validatorIDs[i]] = offlineBlocks[i]; } } struct _SealEpochRewardsCtx { uint256[] baseRewardWeights; uint256 totalBaseRewardWeight; uint256[] txRewardWeights; uint256 totalTxRewardWeight; uint256 epochDuration; uint256 epochFee; } function _sealEpoch_rewards( EpochSnapshot storage snapshot, uint256[] memory validatorIDs, uint256[] memory uptimes, uint256[] memory accumulatedOriginatedTxsFee ) internal { _SealEpochRewardsCtx memory ctx = _SealEpochRewardsCtx( new uint256[](validatorIDs.length), 0, new uint256[](validatorIDs.length), 0, 0, 0 ); EpochSnapshot storage prevSnapshot = getEpochSnapshot[ currentEpoch().sub(1) ]; ctx.epochDuration = 1; if (_now() > prevSnapshot.endTime) { ctx.epochDuration = _now() - prevSnapshot.endTime; } for (uint256 i = 0; i < validatorIDs.length; i++) { uint256 prevAccumulatedTxsFee = prevSnapshot .accumulatedOriginatedTxsFee[validatorIDs[i]]; uint256 originatedTxsFee = 0; if (accumulatedOriginatedTxsFee[i] > prevAccumulatedTxsFee) { originatedTxsFee = accumulatedOriginatedTxsFee[i] - prevAccumulatedTxsFee; } // txRewardWeight = {originatedTxsFee} * {uptime} // originatedTxsFee is roughly proportional to {uptime} * {stake}, so the whole formula is roughly // {stake} * {uptime} ^ 2 ctx.txRewardWeights[i] = (originatedTxsFee * uptimes[i]) / ctx.epochDuration; ctx.totalTxRewardWeight = ctx.totalTxRewardWeight.add( ctx.txRewardWeights[i] ); ctx.epochFee = ctx.epochFee.add(originatedTxsFee); } for (uint256 i = 0; i < validatorIDs.length; i++) { // baseRewardWeight = {stake} * {uptime ^ 2} ctx.baseRewardWeights[i] = (((snapshot.receivedStake[validatorIDs[i]] * uptimes[i]) / ctx.epochDuration) * uptimes[i]) / ctx.epochDuration; ctx.totalBaseRewardWeight = ctx.totalBaseRewardWeight.add( ctx.baseRewardWeights[i] ); } for (uint256 i = 0; i < validatorIDs.length; i++) { uint256 rawReward = _calcRawValidatorEpochBaseReward( ctx.epochDuration, baseRewardPerSecond, ctx.baseRewardWeights[i], ctx.totalBaseRewardWeight ); rawReward = rawReward.add( _calcRawValidatorEpochTxReward( ctx.epochFee, ctx.txRewardWeights[i], ctx.totalTxRewardWeight ) ); uint256 validatorID = validatorIDs[i]; address validatorAddr = getValidator[validatorID].auth; // accounting validator's commission uint256 commissionRewardFull = _calcValidatorCommission( rawReward, validatorCommission() ); uint256 selfStake = getStake[validatorAddr][validatorID]; if (selfStake != 0) { uint256 lCommissionRewardFull = (commissionRewardFull * getLockedStake(validatorAddr, validatorID)) / selfStake; uint256 uCommissionRewardFull = commissionRewardFull - lCommissionRewardFull; Rewards memory lCommissionReward = _scaleLockupReward( lCommissionRewardFull, getLockupInfo[validatorAddr][validatorID].duration ); Rewards memory uCommissionReward = _scaleLockupReward( uCommissionRewardFull, 0 ); _rewardsStash[validatorAddr][validatorID] = sumRewards( _rewardsStash[validatorAddr][validatorID], lCommissionReward, uCommissionReward ); getStashedLockupRewards[validatorAddr][ validatorID ] = sumRewards( getStashedLockupRewards[validatorAddr][validatorID], lCommissionReward, uCommissionReward ); } // accounting reward per token for delegators uint256 delegatorsReward = rawReward - commissionRewardFull; // note: use latest stake for the sake of rewards distribution accuracy, not snapshot.receivedStake uint256 receivedStake = getValidator[validatorID].receivedStake; uint256 rewardPerToken = 0; if (receivedStake != 0) { rewardPerToken = (delegatorsReward * Decimal.unit()) / receivedStake; } snapshot.accumulatedRewardPerToken[validatorID] = prevSnapshot.accumulatedRewardPerToken[validatorID] + rewardPerToken; // snapshot.accumulatedOriginatedTxsFee[ validatorID ] = accumulatedOriginatedTxsFee[i]; snapshot.accumulatedUptime[validatorID] = prevSnapshot.accumulatedUptime[validatorID] + uptimes[i]; } snapshot.epochFee = ctx.epochFee; snapshot.totalBaseRewardWeight = ctx.totalBaseRewardWeight; snapshot.totalTxRewardWeight = ctx.totalTxRewardWeight; } function sealEpoch( uint256[] calldata offlineTime, uint256[] calldata offlineBlocks, uint256[] calldata uptimes, uint256[] calldata originatedTxsFee ) external onlyDriver { EpochSnapshot storage snapshot = getEpochSnapshot[currentEpoch()]; uint256[] memory validatorIDs = snapshot.validatorIDs; _sealEpoch_offline(snapshot, validatorIDs, offlineTime, offlineBlocks); _sealEpoch_rewards(snapshot, validatorIDs, uptimes, originatedTxsFee); currentSealedEpoch = currentEpoch(); snapshot.endTime = _now(); snapshot.baseRewardPerSecond = baseRewardPerSecond; snapshot.totalSupply = totalSupply; } function sealEpochValidators(uint256[] calldata nextValidatorIDs) external onlyDriver { // fill data for the next snapshot EpochSnapshot storage snapshot = getEpochSnapshot[currentEpoch()]; for (uint256 i = 0; i < nextValidatorIDs.length; i++) { uint256 validatorID = nextValidatorIDs[i]; uint256 receivedStake = getValidator[validatorID].receivedStake; snapshot.receivedStake[validatorID] = receivedStake; snapshot.totalStake = snapshot.totalStake.add(receivedStake); } snapshot.validatorIDs = nextValidatorIDs; } function _now() internal view returns (uint256) { return block.timestamp; } function epochEndTime(uint256 epoch) internal view returns (uint256) { return getEpochSnapshot[epoch].endTime; } function isLockedUp(address delegator, uint256 toValidatorID) public view returns (bool) { return getLockupInfo[delegator][toValidatorID].endTime != 0 && getLockupInfo[delegator][toValidatorID].lockedStake != 0 && _now() <= getLockupInfo[delegator][toValidatorID].endTime; } function _isLockedUpAtEpoch( address delegator, uint256 toValidatorID, uint256 epoch ) internal view returns (bool) { return getLockupInfo[delegator][toValidatorID].fromEpoch <= epoch && epochEndTime(epoch) <= getLockupInfo[delegator][toValidatorID].endTime; } function _checkAllowedToWithdraw(address delegator, uint256 toValidatorID) internal view returns (bool) { if (stakeTokenizerAddress == address(0)) { return true; } return StakeTokenizer(stakeTokenizerAddress).allowedToWithdrawStake( delegator, toValidatorID ); } function getUnlockedStake(address delegator, uint256 toValidatorID) public view returns (uint256) { if (!isLockedUp(delegator, toValidatorID)) { return getStake[delegator][toValidatorID]; } return getStake[delegator][toValidatorID].sub( getLockupInfo[delegator][toValidatorID].lockedStake ); } function _lockStake( address delegator, uint256 toValidatorID, uint256 lockupDuration, uint256 amount ) internal { require( amount <= getUnlockedStake(delegator, toValidatorID), "not enough stake" ); require( getValidator[toValidatorID].status == OK_STATUS, "validator isn't active" ); require( lockupDuration >= minLockupDuration() && lockupDuration <= maxLockupDuration(), "incorrect duration" ); uint256 endTime = _now().add(lockupDuration); address validatorAddr = getValidator[toValidatorID].auth; if (delegator != validatorAddr) { require( getLockupInfo[validatorAddr][toValidatorID].endTime >= endTime, "validator lockup period will end earlier" ); } _stashRewards(delegator, toValidatorID); // check lockup duration after _stashRewards, which has erased previous lockup if it has unlocked already LockedDelegation storage ld = getLockupInfo[delegator][toValidatorID]; require( lockupDuration >= ld.duration, "lockup duration cannot decrease" ); ld.lockedStake = ld.lockedStake.add(amount); ld.fromEpoch = currentEpoch(); ld.endTime = endTime; ld.duration = lockupDuration; emit LockedUpStake(delegator, toValidatorID, lockupDuration, amount); } function lockStake( uint256 toValidatorID, uint256 lockupDuration, uint256 amount ) public { address delegator = msg.sender; require(amount > 0, "zero amount"); require(!isLockedUp(delegator, toValidatorID), "already locked up"); _lockStake(delegator, toValidatorID, lockupDuration, amount); } function relockStake( uint256 toValidatorID, uint256 lockupDuration, uint256 amount ) public { address delegator = msg.sender; _lockStake(delegator, toValidatorID, lockupDuration, amount); } function _popDelegationUnlockPenalty( address delegator, uint256 toValidatorID, uint256 unlockAmount, uint256 totalAmount ) internal returns (uint256) { uint256 lockupExtraRewardShare = getStashedLockupRewards[delegator][ toValidatorID ].lockupExtraReward.mul(unlockAmount).div(totalAmount); uint256 lockupBaseRewardShare = getStashedLockupRewards[delegator][ toValidatorID ].lockupBaseReward.mul(unlockAmount).div(totalAmount); uint256 penalty = lockupExtraRewardShare + lockupBaseRewardShare / 2; getStashedLockupRewards[delegator][toValidatorID] .lockupExtraReward = getStashedLockupRewards[delegator][ toValidatorID ].lockupExtraReward.sub(lockupExtraRewardShare); getStashedLockupRewards[delegator][toValidatorID] .lockupBaseReward = getStashedLockupRewards[delegator][ toValidatorID ].lockupBaseReward.sub(lockupBaseRewardShare); if (penalty >= unlockAmount) { penalty = unlockAmount; } return penalty; } function unlockStake(uint256 toValidatorID, uint256 amount) external returns (uint256) { address delegator = msg.sender; LockedDelegation storage ld = getLockupInfo[delegator][toValidatorID]; require(amount > 0, "zero amount"); require(isLockedUp(delegator, toValidatorID), "not locked up"); require(amount <= ld.lockedStake, "not enough locked stake"); require( _checkAllowedToWithdraw(delegator, toValidatorID), "outstanding sFTM balance" ); _stashRewards(delegator, toValidatorID); uint256 penalty = _popDelegationUnlockPenalty( delegator, toValidatorID, amount, ld.lockedStake ); ld.lockedStake -= amount; _rawUndelegate(delegator, toValidatorID, penalty); emit UnlockedStake(delegator, toValidatorID, amount, penalty); return penalty; } } contract NodeDriverAuth is Initializable, Ownable { using SafeMath for uint256; SFC internal sfc; NodeDriver internal driver; // Initialize NodeDriverAuth, NodeDriver and SFC in one call to allow fewer genesis transactions function initialize( address _sfc, address _driver, address _owner ) external initializer { Ownable.initialize(_owner); driver = NodeDriver(_driver); sfc = SFC(_sfc); } modifier onlySFC() { require(msg.sender == address(sfc), "caller is not the SFC contract"); _; } modifier onlyDriver() { require( msg.sender == address(driver), "caller is not the NodeDriver contract" ); _; } function migrateTo(address newDriverAuth) external onlyOwner { driver.setBackend(newDriverAuth); } function incBalance(address acc, uint256 diff) external onlySFC { require(acc == address(sfc), "recipient is not the SFC contract"); driver.setBalance(acc, address(acc).balance.add(diff)); } function upgradeCode(address acc, address from) external onlyOwner { require(isContract(acc) && isContract(from), "not a contract"); driver.copyCode(acc, from); } function copyCode(address acc, address from) external onlyOwner { driver.copyCode(acc, from); } function incNonce(address acc, uint256 diff) external onlyOwner { driver.incNonce(acc, diff); } function updateNetworkRules(bytes calldata diff) external onlyOwner { driver.updateNetworkRules(diff); } function updateNetworkVersion(uint256 version) external onlyOwner { driver.updateNetworkVersion(version); } function advanceEpochs(uint256 num) external onlyOwner { driver.advanceEpochs(num); } function updateValidatorWeight(uint256 validatorID, uint256 value) external onlySFC { driver.updateValidatorWeight(validatorID, value); } function updateValidatorPubkey(uint256 validatorID, bytes calldata pubkey) external onlySFC { driver.updateValidatorPubkey(validatorID, pubkey); } function setGenesisValidator( address _auth, uint256 validatorID, bytes calldata pubkey, uint256 status, uint256 createdEpoch, uint256 createdTime, uint256 deactivatedEpoch, uint256 deactivatedTime ) external onlyDriver { sfc.setGenesisValidator( _auth, validatorID, pubkey, status, createdEpoch, createdTime, deactivatedEpoch, deactivatedTime ); } function setGenesisDelegation( address delegator, uint256 toValidatorID, uint256 stake, uint256 lockedStake, uint256 lockupFromEpoch, uint256 lockupEndTime, uint256 lockupDuration, uint256 earlyUnlockPenalty, uint256 rewards ) external onlyDriver { sfc.setGenesisDelegation( delegator, toValidatorID, stake, lockedStake, lockupFromEpoch, lockupEndTime, lockupDuration, earlyUnlockPenalty, rewards ); } function deactivateValidator(uint256 validatorID, uint256 status) external onlyDriver { sfc.deactivateValidator(validatorID, status); } function sealEpochValidators(uint256[] calldata nextValidatorIDs) external onlyDriver { sfc.sealEpochValidators(nextValidatorIDs); } function sealEpoch( uint256[] calldata offlineTimes, uint256[] calldata offlineBlocks, uint256[] calldata uptimes, uint256[] calldata originatedTxsFee ) external onlyDriver { sfc.sealEpoch(offlineTimes, offlineBlocks, uptimes, originatedTxsFee); } function isContract(address account) internal view returns (bool) { uint256 size; // solhint-disable-next-line no-inline-assembly assembly { size := extcodesize(account) } return size > 0; } } contract NodeDriver is Initializable { SFC internal sfc; NodeDriver internal backend; EVMWriter internal evmWriter; event UpdatedBackend(address indexed backend); function setBackend(address _backend) external onlyBackend { emit UpdatedBackend(_backend); backend = NodeDriver(_backend); } modifier onlyBackend() { require(msg.sender == address(backend), "caller is not the backend"); _; } event UpdateValidatorWeight(uint256 indexed validatorID, uint256 weight); event UpdateValidatorPubkey(uint256 indexed validatorID, bytes pubkey); event UpdateNetworkRules(bytes diff); event UpdateNetworkVersion(uint256 version); event AdvanceEpochs(uint256 num); function initialize(address _backend, address _evmWriterAddress) external initializer { backend = NodeDriver(_backend); emit UpdatedBackend(_backend); evmWriter = EVMWriter(_evmWriterAddress); } function setBalance(address acc, uint256 value) external onlyBackend { evmWriter.setBalance(acc, value); } function copyCode(address acc, address from) external onlyBackend { evmWriter.copyCode(acc, from); } function swapCode(address acc, address with) external onlyBackend { evmWriter.swapCode(acc, with); } function setStorage( address acc, bytes32 key, bytes32 value ) external onlyBackend { evmWriter.setStorage(acc, key, value); } function incNonce(address acc, uint256 diff) external onlyBackend { evmWriter.incNonce(acc, diff); } function updateNetworkRules(bytes calldata diff) external onlyBackend { emit UpdateNetworkRules(diff); } function updateNetworkVersion(uint256 version) external onlyBackend { emit UpdateNetworkVersion(version); } function advanceEpochs(uint256 num) external onlyBackend { emit AdvanceEpochs(num); } function updateValidatorWeight(uint256 validatorID, uint256 value) external onlyBackend { emit UpdateValidatorWeight(validatorID, value); } function updateValidatorPubkey(uint256 validatorID, bytes calldata pubkey) external onlyBackend { emit UpdateValidatorPubkey(validatorID, pubkey); } modifier onlyNode() { require(msg.sender == address(0), "not callable"); _; } // Methods which are called only by the node function setGenesisValidator( address _auth, uint256 validatorID, bytes calldata pubkey, uint256 status, uint256 createdEpoch, uint256 createdTime, uint256 deactivatedEpoch, uint256 deactivatedTime ) external onlyNode { backend.setGenesisValidator( _auth, validatorID, pubkey, status, createdEpoch, createdTime, deactivatedEpoch, deactivatedTime ); } function setGenesisDelegation( address delegator, uint256 toValidatorID, uint256 stake, uint256 lockedStake, uint256 lockupFromEpoch, uint256 lockupEndTime, uint256 lockupDuration, uint256 earlyUnlockPenalty, uint256 rewards ) external onlyNode { backend.setGenesisDelegation( delegator, toValidatorID, stake, lockedStake, lockupFromEpoch, lockupEndTime, lockupDuration, earlyUnlockPenalty, rewards ); } function deactivateValidator(uint256 validatorID, uint256 status) external onlyNode { backend.deactivateValidator(validatorID, status); } function sealEpochValidators(uint256[] calldata nextValidatorIDs) external onlyNode { backend.sealEpochValidators(nextValidatorIDs); } function sealEpoch( uint256[] calldata offlineTimes, uint256[] calldata offlineBlocks, uint256[] calldata uptimes, uint256[] calldata originatedTxsFee ) external onlyNode { backend.sealEpoch( offlineTimes, offlineBlocks, uptimes, originatedTxsFee ); } } interface EVMWriter { function setBalance(address acc, uint256 value) external; function copyCode(address acc, address from) external; function swapCode(address acc, address with) external; function setStorage( address acc, bytes32 key, bytes32 value ) external; function incNonce(address acc, uint256 diff) external; }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"validatorID","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"status","type":"uint256"}],"name":"ChangedValidatorStatus","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"delegator","type":"address"},{"indexed":true,"internalType":"uint256","name":"toValidatorID","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"lockupExtraReward","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"lockupBaseReward","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"unlockedReward","type":"uint256"}],"name":"ClaimedRewards","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"validatorID","type":"uint256"},{"indexed":true,"internalType":"address","name":"auth","type":"address"},{"indexed":false,"internalType":"uint256","name":"createdEpoch","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"createdTime","type":"uint256"}],"name":"CreatedValidator","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"validatorID","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"deactivatedEpoch","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"deactivatedTime","type":"uint256"}],"name":"DeactivatedValidator","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"delegator","type":"address"},{"indexed":true,"internalType":"uint256","name":"toValidatorID","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Delegated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"string","name":"justification","type":"string"}],"name":"InflatedFTM","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"delegator","type":"address"},{"indexed":true,"internalType":"uint256","name":"validatorID","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"duration","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"LockedUpStake","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"delegator","type":"address"},{"indexed":true,"internalType":"uint256","name":"validatorID","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"RefundedSlashedLegacyDelegation","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"delegator","type":"address"},{"indexed":true,"internalType":"uint256","name":"toValidatorID","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"lockupExtraReward","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"lockupBaseReward","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"unlockedReward","type":"uint256"}],"name":"RestakedRewards","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"delegator","type":"address"},{"indexed":true,"internalType":"uint256","name":"toValidatorID","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"wrID","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Undelegated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"delegator","type":"address"},{"indexed":true,"internalType":"uint256","name":"validatorID","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"penalty","type":"uint256"}],"name":"UnlockedStake","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"UpdatedBaseRewardPerSec","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"blocksNum","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"period","type":"uint256"}],"name":"UpdatedOfflinePenaltyThreshold","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"validatorID","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"refundRatio","type":"uint256"}],"name":"UpdatedSlashingRefundRatio","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"delegator","type":"address"},{"indexed":true,"internalType":"uint256","name":"toValidatorID","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"wrID","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Withdrawn","type":"event"},{"constant":false,"inputs":[{"internalType":"uint256","name":"validatorID","type":"uint256"},{"internalType":"bool","name":"syncPubkey","type":"bool"}],"name":"_syncValidator","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"baseRewardPerSecond","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"toValidatorID","type":"uint256"}],"name":"claimRewards","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"contractCommission","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes","name":"pubkey","type":"bytes"}],"name":"createValidator","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[],"name":"currentEpoch","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"currentSealedEpoch","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"validatorID","type":"uint256"},{"internalType":"uint256","name":"status","type":"uint256"}],"name":"deactivateValidator","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"toValidatorID","type":"uint256"}],"name":"delegate","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"epoch","type":"uint256"},{"internalType":"uint256","name":"validatorID","type":"uint256"}],"name":"getEpochAccumulatedOriginatedTxsFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"epoch","type":"uint256"},{"internalType":"uint256","name":"validatorID","type":"uint256"}],"name":"getEpochAccumulatedRewardPerToken","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"epoch","type":"uint256"},{"internalType":"uint256","name":"validatorID","type":"uint256"}],"name":"getEpochAccumulatedUptime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"epoch","type":"uint256"},{"internalType":"uint256","name":"validatorID","type":"uint256"}],"name":"getEpochOfflineBlocks","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"epoch","type":"uint256"},{"internalType":"uint256","name":"validatorID","type":"uint256"}],"name":"getEpochOfflineTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"epoch","type":"uint256"},{"internalType":"uint256","name":"validatorID","type":"uint256"}],"name":"getEpochReceivedStake","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"getEpochSnapshot","outputs":[{"internalType":"uint256","name":"endTime","type":"uint256"},{"internalType":"uint256","name":"epochFee","type":"uint256"},{"internalType":"uint256","name":"totalBaseRewardWeight","type":"uint256"},{"internalType":"uint256","name":"totalTxRewardWeight","type":"uint256"},{"internalType":"uint256","name":"baseRewardPerSecond","type":"uint256"},{"internalType":"uint256","name":"totalStake","type":"uint256"},{"internalType":"uint256","name":"totalSupply","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"epoch","type":"uint256"}],"name":"getEpochValidatorIDs","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"delegator","type":"address"},{"internalType":"uint256","name":"toValidatorID","type":"uint256"}],"name":"getLockedStake","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"getLockupInfo","outputs":[{"internalType":"uint256","name":"lockedStake","type":"uint256"},{"internalType":"uint256","name":"fromEpoch","type":"uint256"},{"internalType":"uint256","name":"endTime","type":"uint256"},{"internalType":"uint256","name":"duration","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"validatorID","type":"uint256"}],"name":"getSelfStake","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"getStake","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"getStashedLockupRewards","outputs":[{"internalType":"uint256","name":"lockupExtraReward","type":"uint256"},{"internalType":"uint256","name":"lockupBaseReward","type":"uint256"},{"internalType":"uint256","name":"unlockedReward","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"delegator","type":"address"},{"internalType":"uint256","name":"toValidatorID","type":"uint256"}],"name":"getUnlockedStake","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"getValidator","outputs":[{"internalType":"uint256","name":"status","type":"uint256"},{"internalType":"uint256","name":"deactivatedTime","type":"uint256"},{"internalType":"uint256","name":"deactivatedEpoch","type":"uint256"},{"internalType":"uint256","name":"receivedStake","type":"uint256"},{"internalType":"uint256","name":"createdEpoch","type":"uint256"},{"internalType":"uint256","name":"createdTime","type":"uint256"},{"internalType":"address","name":"auth","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"getValidatorID","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"getValidatorPubkey","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"getWithdrawalRequest","outputs":[{"internalType":"uint256","name":"epoch","type":"uint256"},{"internalType":"uint256","name":"time","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"sealedEpoch","type":"uint256"},{"internalType":"uint256","name":"_totalSupply","type":"uint256"},{"internalType":"address","name":"nodeDriver","type":"address"},{"internalType":"address","name":"owner","type":"address"}],"name":"initialize","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"delegator","type":"address"},{"internalType":"uint256","name":"toValidatorID","type":"uint256"}],"name":"isLockedUp","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"isOwner","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"validatorID","type":"uint256"}],"name":"isSlashed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"lastValidatorID","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"toValidatorID","type":"uint256"},{"internalType":"uint256","name":"lockupDuration","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"lockStake","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"maxDelegatedRatio","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[],"name":"maxLockupDuration","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[],"name":"minLockupDuration","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[],"name":"minSelfStake","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":false,"inputs":[{"internalType":"address payable","name":"receiver","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"string","name":"justification","type":"string"}],"name":"mintFTM","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"offlinePenaltyThreshold","outputs":[{"internalType":"uint256","name":"blocksNum","type":"uint256"},{"internalType":"uint256","name":"time","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"delegator","type":"address"},{"internalType":"uint256","name":"toValidatorID","type":"uint256"}],"name":"pendingRewards","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"toValidatorID","type":"uint256"},{"internalType":"uint256","name":"lockupDuration","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"relockStake","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"renounceOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"toValidatorID","type":"uint256"}],"name":"restakeRewards","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"delegator","type":"address"},{"internalType":"uint256","name":"validatorID","type":"uint256"}],"name":"rewardsStash","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256[]","name":"offlineTime","type":"uint256[]"},{"internalType":"uint256[]","name":"offlineBlocks","type":"uint256[]"},{"internalType":"uint256[]","name":"uptimes","type":"uint256[]"},{"internalType":"uint256[]","name":"originatedTxsFee","type":"uint256[]"}],"name":"sealEpoch","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256[]","name":"nextValidatorIDs","type":"uint256[]"}],"name":"sealEpochValidators","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"delegator","type":"address"},{"internalType":"uint256","name":"toValidatorID","type":"uint256"},{"internalType":"uint256","name":"stake","type":"uint256"},{"internalType":"uint256","name":"lockedStake","type":"uint256"},{"internalType":"uint256","name":"lockupFromEpoch","type":"uint256"},{"internalType":"uint256","name":"lockupEndTime","type":"uint256"},{"internalType":"uint256","name":"lockupDuration","type":"uint256"},{"internalType":"uint256","name":"earlyUnlockPenalty","type":"uint256"},{"internalType":"uint256","name":"rewards","type":"uint256"}],"name":"setGenesisDelegation","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"auth","type":"address"},{"internalType":"uint256","name":"validatorID","type":"uint256"},{"internalType":"bytes","name":"pubkey","type":"bytes"},{"internalType":"uint256","name":"status","type":"uint256"},{"internalType":"uint256","name":"createdEpoch","type":"uint256"},{"internalType":"uint256","name":"createdTime","type":"uint256"},{"internalType":"uint256","name":"deactivatedEpoch","type":"uint256"},{"internalType":"uint256","name":"deactivatedTime","type":"uint256"}],"name":"setGenesisValidator","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"slashingRefundRatio","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"stakeTokenizerAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"delegator","type":"address"},{"internalType":"uint256","name":"toValidatorID","type":"uint256"}],"name":"stashRewards","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"stashedRewardsUntilEpoch","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"totalActiveStake","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"totalSlashedStake","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"totalStake","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"toValidatorID","type":"uint256"},{"internalType":"uint256","name":"wrID","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"undelegate","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"toValidatorID","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"unlockStake","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"unlockedRewardRatio","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"value","type":"uint256"}],"name":"updateBaseRewardPerSecond","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"blocksNum","type":"uint256"},{"internalType":"uint256","name":"time","type":"uint256"}],"name":"updateOfflinePenaltyThreshold","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"validatorID","type":"uint256"},{"internalType":"uint256","name":"refundRatio","type":"uint256"}],"name":"updateSlashingRefundRatio","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"updateStakeTokenizerAddress","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"int256","name":"diff","type":"int256"}],"name":"updateTotalSupply","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"validatorCommission","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[],"name":"version","outputs":[{"internalType":"bytes3","name":"","type":"bytes3"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"toValidatorID","type":"uint256"},{"internalType":"uint256","name":"wrID","type":"uint256"}],"name":"withdraw","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"withdrawalPeriodEpochs","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[],"name":"withdrawalPeriodTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"}]
Contract Creation Code
608060405234801561001057600080fd5b50615bcc80620000216000396000f3fe6080604052600436106104805760003560e01c80637cacb1d61161025e578063b88a37e211610143578063d9a7c1f9116100bb578063e08d7e661161008a578063e2f8c3361161006f578063e2f8c33614611259578063ebdf104c146112eb578063f2fde38b1461145e57610480565b8063e08d7e66146111ac578063e261641a1461122957610480565b8063d9a7c1f914611101578063dc31e1af14611116578063de67f21514611146578063df00c9221461117c57610480565b8063c65ee0e111610112578063cc8343aa116100f7578063cc8343aa1461105d578063cfd476631461108f578063cfdbb7cd146110c857610480565b8063c65ee0e11461101e578063c7be95de1461104857610480565b8063b88a37e214610f2f578063bd14d90714610fa9578063c3de580e14610fdf578063c5f530af1461100957610480565b8063a198d229116101d6578063a86a056f116101a5578063b6d9edd51161018a578063b6d9edd514610eb7578063b810e41114610ee1578063b82b842714610f1a57610480565b8063a86a056f14610e13578063b5d8962714610e4c57610480565b8063a198d22914610d2b578063a2f6e6bc14610d5b578063a5a470ad14610d8e578063a778651514610dfe57610480565b80638cddb0151161022d5780638f32d59b116102125780638f32d59b14610c8657806396c7ee4614610caf5780639fa6dd3514610d0e57610480565b80638cddb01514610c385780638da5cb5b14610c7157610480565b80637cacb1d614610b3f578063854873e114610b545780638b0e9f3f14610bf35780638b1a0d1114610c0857610480565b8063346bdcfb116103845780635e2308d2116102fc578063650acd66116102cb5780636f498663116102b05780636f49866314610adc578063715018a614610b155780637667180814610b2a57610480565b8063650acd6614610a8e578063670322f814610aa357610480565b80635e2308d2146107475780635fab23a814610a105780636099ecb214610a2557806361e53fcc14610a5e57610480565b80634f864df41161035357806354fd4d501161033857806354fd4d501461096c5780635601fe01146109b657806358f95b80146109e057610480565b80634f864df41461088b5780634feb92f3146108c157610480565b8063346bdcfb1461079f57806339b80c00146107c9578063441a3e701461082b5780634f7c4efb1461085b57610480565b806318160ddd116104175780631f270152116103e65780632709275e116103cb5780632709275e1461074757806328f731481461075c5780632cedb0971461077157610480565b80631f270152146106d55780632265f2841461073257610480565b806318160ddd146105fb57806318f628d4146106105780631d3ac42c146106755780631e702f83146106a557610480565b80630d4955e3116104535780630d4955e3146105675780630d7b26091461057c5780630e559d821461059157806312622d0e146105c257610480565b80630135b1db14610485578063019e2729146104ca57806308c36874146105135780630962ef791461053d575b600080fd5b34801561049157600080fd5b506104b8600480360360208110156104a857600080fd5b50356001600160a01b0316611491565b60408051918252519081900360200190f35b3480156104d657600080fd5b50610511600480360360808110156104ed57600080fd5b508035906020810135906001600160a01b03604082013581169160600135166114a3565b005b34801561051f57600080fd5b506105116004803603602081101561053657600080fd5b503561161a565b34801561054957600080fd5b506105116004803603602081101561056057600080fd5b50356116e6565b34801561057357600080fd5b506104b8611831565b34801561058857600080fd5b506104b861183a565b34801561059d57600080fd5b506105a6611841565b604080516001600160a01b039092168252519081900360200190f35b3480156105ce57600080fd5b506104b8600480360360408110156105e557600080fd5b506001600160a01b038135169060200135611850565b34801561060757600080fd5b506104b86118d9565b34801561061c57600080fd5b50610511600480360361012081101561063457600080fd5b506001600160a01b038135169060208101359060408101359060608101359060808101359060a08101359060c08101359060e08101359061010001356118df565b34801561068157600080fd5b506104b86004803603604081101561069857600080fd5b5080359060200135611a3f565b3480156106b157600080fd5b50610511600480360360408110156106c857600080fd5b5080359060200135611c3e565b3480156106e157600080fd5b50610714600480360360608110156106f857600080fd5b506001600160a01b038135169060208101359060400135611ced565b60408051938452602084019290925282820152519081900360600190f35b34801561073e57600080fd5b506104b8611d1f565b34801561075357600080fd5b506104b8611d31565b34801561076857600080fd5b506104b8611d4d565b34801561077d57600080fd5b50610786611d53565b6040805192835260208301919091528051918290030190f35b3480156107ab57600080fd5b50610511600480360360208110156107c257600080fd5b5035611d5d565b3480156107d557600080fd5b506107f3600480360360208110156107ec57600080fd5b5035611ddc565b604080519788526020880196909652868601949094526060860192909252608085015260a084015260c0830152519081900360e00190f35b34801561083757600080fd5b506105116004803603604081101561084e57600080fd5b5080359060200135611e1e565b34801561086757600080fd5b506105116004803603604081101561087e57600080fd5b5080359060200135612241565b34801561089757600080fd5b50610511600480360360608110156108ae57600080fd5b5080359060208101359060400135612385565b3480156108cd57600080fd5b5061051160048036036101008110156108e557600080fd5b6001600160a01b038235169160208101359181019060608101604082013564010000000081111561091557600080fd5b82018360208201111561092757600080fd5b8035906020019184600183028401116401000000008311171561094957600080fd5b91935091508035906020810135906040810135906060810135906080013561261e565b34801561097857600080fd5b506109816126c4565b604080517fffffff00000000000000000000000000000000000000000000000000000000009092168252519081900360200190f35b3480156109c257600080fd5b506104b8600480360360208110156109d957600080fd5b50356126e8565b3480156109ec57600080fd5b506104b860048036036040811015610a0357600080fd5b508035906020013561271e565b348015610a1c57600080fd5b506104b861273b565b348015610a3157600080fd5b506104b860048036036040811015610a4857600080fd5b506001600160a01b038135169060200135612741565b348015610a6a57600080fd5b506104b860048036036040811015610a8157600080fd5b508035906020013561277f565b348015610a9a57600080fd5b506104b86127a0565b348015610aaf57600080fd5b506104b860048036036040811015610ac657600080fd5b506001600160a01b0381351690602001356127a5565b348015610ae857600080fd5b506104b860048036036040811015610aff57600080fd5b506001600160a01b0381351690602001356127e6565b348015610b2157600080fd5b50610511612850565b348015610b3657600080fd5b506104b861290b565b348015610b4b57600080fd5b506104b8612914565b348015610b6057600080fd5b50610b7e60048036036020811015610b7757600080fd5b503561291a565b6040805160208082528351818301528351919283929083019185019080838360005b83811015610bb8578181015183820152602001610ba0565b50505050905090810190601f168015610be55780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b348015610bff57600080fd5b506104b86129d3565b348015610c1457600080fd5b5061051160048036036040811015610c2b57600080fd5b50803590602001356129d9565b348015610c4457600080fd5b5061051160048036036040811015610c5b57600080fd5b506001600160a01b038135169060200135612a7b565b348015610c7d57600080fd5b506105a6612ad6565b348015610c9257600080fd5b50610c9b612ae5565b604080519115158252519081900360200190f35b348015610cbb57600080fd5b50610ce860048036036040811015610cd257600080fd5b506001600160a01b038135169060200135612af6565b604080519485526020850193909352838301919091526060830152519081900360800190f35b61051160048036036020811015610d2457600080fd5b5035612b28565b348015610d3757600080fd5b506104b860048036036040811015610d4e57600080fd5b5080359060200135612b33565b348015610d6757600080fd5b5061051160048036036020811015610d7e57600080fd5b50356001600160a01b0316612b54565b61051160048036036020811015610da457600080fd5b810190602081018135640100000000811115610dbf57600080fd5b820183602082011115610dd157600080fd5b80359060200191846001830284011164010000000083111715610df357600080fd5b509092509050612be7565b348015610e0a57600080fd5b506104b8612ce2565b348015610e1f57600080fd5b506104b860048036036040811015610e3657600080fd5b506001600160a01b038135169060200135612cf8565b348015610e5857600080fd5b50610e7660048036036020811015610e6f57600080fd5b5035612d15565b604080519788526020880196909652868601949094526060860192909252608085015260a08401526001600160a01b031660c0830152519081900360e00190f35b348015610ec357600080fd5b5061051160048036036020811015610eda57600080fd5b5035612d5b565b348015610eed57600080fd5b5061071460048036036040811015610f0457600080fd5b506001600160a01b038135169060200135612e4d565b348015610f2657600080fd5b506104b8612e79565b348015610f3b57600080fd5b50610f5960048036036020811015610f5257600080fd5b5035612e80565b60408051602080825283518183015283519192839290830191858101910280838360005b83811015610f95578181015183820152602001610f7d565b505050509050019250505060405180910390f35b348015610fb557600080fd5b5061051160048036036060811015610fcc57600080fd5b5080359060208101359060400135612ee5565b348015610feb57600080fd5b50610c9b6004803603602081101561100257600080fd5b5035612ef8565b34801561101557600080fd5b506104b8612f0f565b34801561102a57600080fd5b506104b86004803603602081101561104157600080fd5b5035612f1d565b34801561105457600080fd5b506104b8612f2f565b34801561106957600080fd5b506105116004803603604081101561108057600080fd5b50803590602001351515612f35565b34801561109b57600080fd5b506104b8600480360360408110156110b257600080fd5b506001600160a01b03813516906020013561316e565b3480156110d457600080fd5b50610c9b600480360360408110156110eb57600080fd5b506001600160a01b03813516906020013561318b565b34801561110d57600080fd5b506104b8613221565b34801561112257600080fd5b506104b86004803603604081101561113957600080fd5b5080359060200135613227565b34801561115257600080fd5b506105116004803603606081101561116957600080fd5b5080359060208101359060400135613248565b34801561118857600080fd5b506104b86004803603604081101561119f57600080fd5b5080359060200135613303565b3480156111b857600080fd5b50610511600480360360208110156111cf57600080fd5b8101906020810181356401000000008111156111ea57600080fd5b8201836020820111156111fc57600080fd5b8035906020019184602083028401116401000000008311171561121e57600080fd5b509092509050613324565b34801561123557600080fd5b506104b86004803603604081101561124c57600080fd5b50803590602001356133fe565b34801561126557600080fd5b506105116004803603606081101561127c57600080fd5b6001600160a01b03823516916020810135918101906060810160408201356401000000008111156112ac57600080fd5b8201836020820111156112be57600080fd5b803590602001918460018302840111640100000000831117156112e057600080fd5b50909250905061341f565b3480156112f757600080fd5b506105116004803603608081101561130e57600080fd5b81019060208101813564010000000081111561132957600080fd5b82018360208201111561133b57600080fd5b8035906020019184602083028401116401000000008311171561135d57600080fd5b91939092909160208101903564010000000081111561137b57600080fd5b82018360208201111561138d57600080fd5b803590602001918460208302840111640100000000831117156113af57600080fd5b9193909290916020810190356401000000008111156113cd57600080fd5b8201836020820111156113df57600080fd5b8035906020019184602083028401116401000000008311171561140157600080fd5b91939092909160208101903564010000000081111561141f57600080fd5b82018360208201111561143157600080fd5b8035906020019184602083028401116401000000008311171561145357600080fd5b50909250905061354e565b34801561146a57600080fd5b506105116004803603602081101561148157600080fd5b50356001600160a01b031661372a565b60696020526000908152604090205481565b600054610100900460ff16806114bc57506114bc61378c565b806114ca575060005460ff16155b6115055760405162461bcd60e51b815260040180806020018281038252602e815260200180615acc602e913960400191505060405180910390fd5b600054610100900460ff1615801561156b57600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff909116610100171660011790555b61157482613792565b6067859055606680547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b03851617905560768490556755cfe697852e904c6075556103e86078556203f4806079556115d26138f3565b600086815260776020526040902060070155801561161357600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff1690555b5050505050565b33611623615931565b61162d82846138f7565b602081015181519192506000916116499163ffffffff6139fc16565b905061166c83856116678560400151856139fc90919063ffffffff16565b613a56565b6001600160a01b0383166000818152607360209081526040808320888452825291829020805485019055845185820151868401518451928352928201528083019190915290518692917f4119153d17a36f9597d40e3ab4148d03261a439dddbec4e91799ab7159608e26919081900360600190a350505050565b336116ef615931565b6116f982846138f7565b90506000826001600160a01b0316611736836040015161172a856020015186600001516139fc90919063ffffffff16565b9063ffffffff6139fc16565b604051600081818185875af1925050503d8060008114611772576040519150601f19603f3d011682016040523d82523d6000602084013e611777565b606091505b50509050806117cd576040805162461bcd60e51b815260206004820152601260248201527f4661696c656420746f2073656e642046544d0000000000000000000000000000604482015290519081900360640190fd5b83836001600160a01b03167fc1d8eb6e444b89fb8ff0991c19311c070df704ccb009e210d1462d5b2410bf4584600001518560200151866040015160405180848152602001838152602001828152602001935050505060405180910390a350505050565b6301e133805b90565b6212750090565b607b546001600160a01b031681565b600061185c838361318b565b61188a57506001600160a01b03821660009081526072602090815260408083208484529091529020546118d3565b6001600160a01b0383166000818152607360209081526040808320868452825280832054938352607282528083208684529091529020546118d09163ffffffff613b6016565b90505b92915050565b60765481565b6118e833613ba2565b6119235760405162461bcd60e51b8152600401808060200182810382526029815260200180615a826029913960400191505060405180910390fd5b61192e898989613bb6565b6001600160a01b0389166000908152606f602090815260408083208b8452909152902060020181905561196087613d2d565b8515611a3457868611156119a55760405162461bcd60e51b815260040180806020018281038252602c815260200180615b6c602c913960400191505060405180910390fd5b6001600160a01b03891660008181526073602090815260408083208c845282528083208a8155600181018a90556002810189905560038101889055848452607483528184208d855283529281902086905580518781529182018a9052805192938c9390927f138940e95abffcd789b497bf6188bba3afa5fbd22fb5c42c2f6018d1bf0f4e7892908290030190a3505b505050505050505050565b336000818152607360209081526040808320868452909152812090919083611aae576040805162461bcd60e51b815260206004820152600b60248201527f7a65726f20616d6f756e74000000000000000000000000000000000000000000604482015290519081900360640190fd5b611ab8828661318b565b611b09576040805162461bcd60e51b815260206004820152600d60248201527f6e6f74206c6f636b656420757000000000000000000000000000000000000000604482015290519081900360640190fd5b8054841115611b5f576040805162461bcd60e51b815260206004820152601760248201527f6e6f7420656e6f756768206c6f636b6564207374616b65000000000000000000604482015290519081900360640190fd5b611b698286613dcb565b611bba576040805162461bcd60e51b815260206004820152601860248201527f6f75747374616e64696e67207346544d2062616c616e63650000000000000000604482015290519081900360640190fd5b611bc48286613e86565b506000611bd78387878560000154614051565b825486900383559050611beb838783614182565b85836001600160a01b03167fef6c0c14fe9aa51af36acd791464dec3badbde668b63189b47bfa4e25be9b2b98784604051808381526020018281526020019250505060405180910390a395945050505050565b611c4733613ba2565b611c825760405162461bcd60e51b8152600401808060200182810382526029815260200180615a826029913960400191505060405180910390fd5b80611cd4576040805162461bcd60e51b815260206004820152600c60248201527f77726f6e67207374617475730000000000000000000000000000000000000000604482015290519081900360640190fd5b611cde82826142d8565b611ce9826000612f35565b5050565b607160209081526000938452604080852082529284528284209052825290208054600182015460029092015490919083565b6000611d29614402565b601002905090565b60006064611d3d614402565b601e0281611d4757fe5b04905090565b606d5481565b6078546079549091565b611d65612ae5565b611db6576040805162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b60008112611dcb576076805482019055611dd9565b607680546000839003900390555b50565b607760205280600052604060002060009150905080600701549080600801549080600901549080600a01549080600b01549080600c01549080600d0154905087565b33611e27615931565b506001600160a01b038116600090815260716020908152604080832086845282528083208584528252918290208251606081018452815480825260018301549382019390935260029091015492810192909252611ecb576040805162461bcd60e51b815260206004820152601560248201527f7265717565737420646f65736e27742065786973740000000000000000000000604482015290519081900360640190fd5b611ed58285613dcb565b611f26576040805162461bcd60e51b815260206004820152601860248201527f6f75747374616e64696e67207346544d2062616c616e63650000000000000000604482015290519081900360640190fd5b60208082015182516000878152606890935260409092206001015490919015801590611f62575060008681526068602052604090206001015482115b15611f83575050600084815260686020526040902060018101546002909101545b611f8b612e79565b8201611f956138f3565b1015611fe8576040805162461bcd60e51b815260206004820152601660248201527f6e6f7420656e6f7567682074696d652070617373656400000000000000000000604482015290519081900360640190fd5b611ff06127a0565b8101611ffa61290b565b101561204d576040805162461bcd60e51b815260206004820152601860248201527f6e6f7420656e6f7567682065706f636873207061737365640000000000000000604482015290519081900360640190fd5b6001600160a01b038416600090815260716020908152604080832089845282528083208884529091528120600201549061208688612ef8565b905060006120a88383607a60008d81526020019081526020016000205461440e565b6001600160a01b03881660009081526071602090815260408083208d845282528083208c845290915281208181556001810182905560020155606e805482019055905080831161213f576040805162461bcd60e51b815260206004820152601660248201527f7374616b652069732066756c6c7920736c617368656400000000000000000000604482015290519081900360640190fd5b60006001600160a01b03881661215b858463ffffffff613b6016565b604051600081818185875af1925050503d8060008114612197576040519150601f19603f3d011682016040523d82523d6000602084013e61219c565b606091505b50509050806121f2576040805162461bcd60e51b815260206004820152601260248201527f4661696c656420746f2073656e642046544d0000000000000000000000000000604482015290519081900360640190fd5b888a896001600160a01b03167f75e161b3e824b114fc1a33274bd7091918dd4e639cede50b78b15a4eea956a21876040518082815260200191505060405180910390a450505050505050505050565b612249612ae5565b61229a576040805162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b6122a382612ef8565b6122f4576040805162461bcd60e51b815260206004820152601760248201527f76616c696461746f722069736e277420736c6173686564000000000000000000604482015290519081900360640190fd5b6122fc614402565b81111561233a5760405162461bcd60e51b8152600401808060200182810382526021815260200180615afa6021913960400191505060405180910390fd5b6000828152607a60209081526040918290208390558151838152915184927f047575f43f09a7a093d94ec483064acfc61b7e25c0de28017da442abf99cb91792908290030190a25050565b336123908185613e86565b50600082116123e6576040805162461bcd60e51b815260206004820152600b60248201527f7a65726f20616d6f756e74000000000000000000000000000000000000000000604482015290519081900360640190fd5b6123f08185611850565b821115612444576040805162461bcd60e51b815260206004820152601960248201527f6e6f7420656e6f75676820756e6c6f636b6564207374616b6500000000000000604482015290519081900360640190fd5b61244e8185613dcb565b61249f576040805162461bcd60e51b815260206004820152601860248201527f6f75747374616e64696e67207346544d2062616c616e63650000000000000000604482015290519081900360640190fd5b6001600160a01b0381166000908152607160209081526040808320878452825280832086845290915290206002015415612520576040805162461bcd60e51b815260206004820152601360248201527f7772494420616c72656164792065786973747300000000000000000000000000604482015290519081900360640190fd5b61252b818584614182565b6001600160a01b03811660009081526071602090815260408083208784528252808320868452909152902060020182905561256461290b565b6001600160a01b038216600090815260716020908152604080832088845282528083208784529091529020556125986138f3565b6001600160a01b038216600090815260716020908152604080832088845282528083208784529091528120600101919091556125d5908590612f35565b8284826001600160a01b03167fd3bb4e423fbea695d16b982f9f682dc5f35152e5411646a8a5a79a6b02ba8d57856040518082815260200191505060405180910390a450505050565b61262733613ba2565b6126625760405162461bcd60e51b8152600401808060200182810382526029815260200180615a826029913960400191505060405180910390fd5b6126aa898989898080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152508b92508a91508990508888614470565b606b54881115611a3457606b889055505050505050505050565b7f333032000000000000000000000000000000000000000000000000000000000090565b6000818152606860209081526040808320600601546001600160a01b03168352607282528083208484529091529020545b919050565b600091825260776020908152604080842092845291905290205490565b606e5481565b600061274b615931565b6127558484614637565b8051602082015160408301519293506127779261172a9163ffffffff6139fc16565b949350505050565b60009182526077602090815260408084209284526001909201905290205490565b600390565b60006127b1838361318b565b6127bd575060006118d3565b506001600160a01b03919091166000908152607360209081526040808320938352929052205490565b60006127f0615931565b506001600160a01b0383166000908152606f602090815260408083208584528252918290208251606081018452815480825260018301549382018490526002909201549381018490529261277792909161172a919063ffffffff6139fc16565b612858612ae5565b6128a9576040805162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b6033546040516000916001600160a01b0316907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a3603380547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055565b60675460010190565b60675481565b606a6020908152600091825260409182902080548351601f60027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff610100600186161502019093169290920491820184900484028101840190945280845290918301828280156129cb5780601f106129a0576101008083540402835291602001916129cb565b820191906000526020600020905b8154815290600101906020018083116129ae57829003601f168201915b505050505081565b606c5481565b6129e1612ae5565b612a32576040805162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b60798190556078829055604080518381526020810183905281517f702756a07c05d0bbfd06fc17b67951a5f4deb7bb6b088407e68a58969daf2a34929181900390910190a15050565b612a858282613e86565b611ce9576040805162461bcd60e51b815260206004820152601060248201527f6e6f7468696e6720746f20737461736800000000000000000000000000000000604482015290519081900360640190fd5b6033546001600160a01b031690565b6033546001600160a01b0316331490565b607360209081526000928352604080842090915290825290208054600182015460028301546003909301549192909184565b611dd9338234613a56565b60009182526077602090815260408084209284526005909201905290205490565b612b5c612ae5565b612bad576040805162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b607b80547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0392909216919091179055565b612bef612f0f565b341015612c43576040805162461bcd60e51b815260206004820152601760248201527f696e73756666696369656e742073656c662d7374616b65000000000000000000604482015290519081900360640190fd5b80612c95576040805162461bcd60e51b815260206004820152600c60248201527f656d707479207075626b65790000000000000000000000000000000000000000604482015290519081900360640190fd5b612cd53383838080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506146a592505050565b611ce933606b5434613a56565b60006064612cee614402565b600f0281611d4757fe5b607060209081526000928352604080842090915290825290205481565b606860205260009081526040902080546001820154600283015460038401546004850154600586015460069096015494959394929391929091906001600160a01b031687565b612d63612ae5565b612db4576040805162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b6801c985c8903591eb20811115612e12576040805162461bcd60e51b815260206004820152601b60248201527f746f6f206c617267652072657761726420706572207365636f6e640000000000604482015290519081900360640190fd5b60758190556040805182815290517f8cd9dae1bbea2bc8a5e80ffce2c224727a25925130a03ae100619a8861ae23969181900360200190a150565b607460209081526000928352604080842090915290825290208054600182015460029092015490919083565b62093a8090565b600081815260776020908152604091829020600601805483518184028101840190945280845260609392830182828015612ed957602002820191906000526020600020905b815481526020019060010190808311612ec5575b50505050509050919050565b33612ef2818585856146d0565b50505050565b600090815260686020526040902054608016151590565b6969e10de76676d080000090565b607a6020526000908152604090205481565b606b5481565b612f3e826149a1565b612f8f576040805162461bcd60e51b815260206004820152601760248201527f76616c696461746f7220646f65736e2774206578697374000000000000000000604482015290519081900360640190fd5b60008281526068602052604090206003810154905415612fad575060005b606654604080517fa4066fbe000000000000000000000000000000000000000000000000000000008152600481018690526024810184905290516001600160a01b039092169163a4066fbe9160448082019260009290919082900301818387803b15801561301a57600080fd5b505af115801561302e573d6000803e3d6000fd5b5050505081801561303e57508015155b15613169576066546000848152606a60205260409081902081517f242a6e3f0000000000000000000000000000000000000000000000000000000081526004810187815260248201938452825460027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6001831615610100020190911604604483018190526001600160a01b039095169463242a6e3f9489949390916064909101908490801561312f5780601f106131045761010080835404028352916020019161312f565b820191906000526020600020905b81548152906001019060200180831161311257829003601f168201915b50509350505050600060405180830381600087803b15801561315057600080fd5b505af1158015613164573d6000803e3d6000fd5b505050505b505050565b607260209081526000928352604080842090915290825290205481565b6001600160a01b0382166000908152607360209081526040808320848452909152812060020154158015906131e257506001600160a01b038316600090815260736020908152604080832085845290915290205415155b80156118d057506001600160a01b03831660009081526073602090815260408083208584529091529020600201546132186138f3565b11159392505050565b60755481565b60009182526077602090815260408084209284526003909201905290205490565b338161329b576040805162461bcd60e51b815260206004820152600b60248201527f7a65726f20616d6f756e74000000000000000000000000000000000000000000604482015290519081900360640190fd5b6132a5818561318b565b156132f7576040805162461bcd60e51b815260206004820152601160248201527f616c7265616479206c6f636b6564207570000000000000000000000000000000604482015290519081900360640190fd5b612ef2818585856146d0565b60009182526077602090815260408084209284526002909201905290205490565b61332d33613ba2565b6133685760405162461bcd60e51b8152600401808060200182810382526029815260200180615a826029913960400191505060405180910390fd5b60006077600061337661290b565b8152602001908152602001600020905060008090505b828110156133ef5760008484838181106133a257fe5b60209081029290920135600081815260688452604080822060030154948890529020839055600c8601549093506133e091508263ffffffff6139fc16565b600c850155505060010161338c565b50612ef2600682018484615952565b60009182526077602090815260408084209284526004909201905290205490565b613427612ae5565b613478576040805162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b61348183613d2d565b6040516001600160a01b0385169084156108fc029085906000818181858888f193505050501580156134b7573d6000803e3d6000fd5b50836001600160a01b03167f9eec469b348bcf64bbfb60e46ce7b160e2e09bf5421496a2cdbc43714c28b8ad84848460405180848152602001806020018281038252848482818152602001925080828437600083820152604051601f9091017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016909201829003965090945050505050a250505050565b61355733613ba2565b6135925760405162461bcd60e51b8152600401808060200182810382526029815260200180615a826029913960400191505060405180910390fd5b6000607760006135a061290b565b8152602001908152602001600020905060608160060180548060200260200160405190810160405280929190818152602001828054801561360057602002820191906000526020600020905b8154815260200190600101908083116135ec575b5050505050905061368782828c8c80806020026020016040519081016040528093929190818152602001838360200280828437600081840152601f19601f820116905080830192505050505050508b8b808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152506149b892505050565b6136f6828288888080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808c0282810182019093528b82529093508b92508a918291850190849080828437600092019190915250614ac792505050565b6136fe61290b565b6067556137096138f3565b600783015550607554600b820155607654600d909101555050505050505050565b613732612ae5565b613783576040805162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b611dd98161510d565b303b1590565b600054610100900460ff16806137ab57506137ab61378c565b806137b9575060005460ff16155b6137f45760405162461bcd60e51b815260040180806020018281038252602e815260200180615acc602e913960400191505060405180910390fd5b600054610100900460ff1615801561385a57600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff909116610100171660011790555b603380547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0384811691909117918290556040519116906000907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a38015611ce957600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff1690555050565b4290565b6138ff615931565b6139098383613e86565b50506001600160a01b0382166000908152606f60209081526040808320848452825280832081516060810183528154808252600183015494820185905260029092015492810183905293926139679261172a9163ffffffff6139fc16565b9050806139bb576040805162461bcd60e51b815260206004820152600c60248201527f7a65726f20726577617264730000000000000000000000000000000000000000604482015290519081900360640190fd5b6001600160a01b0384166000908152606f60209081526040808320868452909152812081815560018101829055600201556139f581613d2d565b5092915050565b6000828201838110156118d0576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b613a5f826149a1565b613ab0576040805162461bcd60e51b815260206004820152601760248201527f76616c696461746f7220646f65736e2774206578697374000000000000000000604482015290519081900360640190fd5b60008281526068602052604090205415613b11576040805162461bcd60e51b815260206004820152601660248201527f76616c696461746f722069736e27742061637469766500000000000000000000604482015290519081900360640190fd5b613b1c838383613bb6565b613b25826151c6565b6131695760405162461bcd60e51b8152600401808060200182810382526029815260200180615b436029913960400191505060405180910390fd5b60006118d083836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f77000081525061520e565b6066546001600160a01b0390811691161490565b60008111613c0b576040805162461bcd60e51b815260206004820152600b60248201527f7a65726f20616d6f756e74000000000000000000000000000000000000000000604482015290519081900360640190fd5b613c158383613e86565b506001600160a01b0383166000908152607260209081526040808320858452909152902054613c4a908263ffffffff6139fc16565b6001600160a01b0384166000908152607260209081526040808320868452825280832093909355606890522060030154613c8a818363ffffffff6139fc16565b600084815260686020526040902060030155606c54613caf908363ffffffff6139fc16565b606c55600083815260686020526040902054613cdc57606d54613cd8908363ffffffff6139fc16565b606d555b613ce7838215612f35565b60408051838152905184916001600160a01b038716917f9a8f44850296624dadfd9c246d17e47171d35727a181bd090aa14bbbe00238bb9181900360200190a350505050565b606654604080517f66e7ea0f0000000000000000000000000000000000000000000000000000000081523060048201526024810184905290516001600160a01b03909216916366e7ea0f9160448082019260009290919082900301818387803b158015613d9957600080fd5b505af1158015613dad573d6000803e3d6000fd5b5050607654613dc5925090508263ffffffff6139fc16565b60765550565b607b546000906001600160a01b0316613de6575060016118d3565b607b54604080517f21d585c30000000000000000000000000000000000000000000000000000000081526001600160a01b03868116600483015260248201869052915191909216916321d585c3916044808301926020929190829003018186803b158015613e5357600080fd5b505afa158015613e67573d6000803e3d6000fd5b505050506040513d6020811015613e7d57600080fd5b50519392505050565b6000613e90615931565b613e9a84846152a5565b9050613ea5836153dd565b6001600160a01b0385166000818152607060209081526040808320888452825280832094909455918152606f825282812086825282528290208251606081018452815481526001820154928101929092526002015491810191909152613f0b9082615438565b6001600160a01b0385166000818152606f6020908152604080832088845282528083208551815585830151600180830191909155958201516002918201559383526074825280832088845282529182902082516060810184528154815294810154918501919091529091015490820152613f859082615438565b6001600160a01b038516600090815260746020908152604080832087845282529182902083518155908301516001820155910151600290910155613fc9848461318b565b61402c576001600160a01b0384166000818152607360209081526040808320878452825280832083815560018082018590556002808301869055600390920185905594845260748352818420888552909252822082815592830182905591909101555b602081015115158061403e5750805115155b8061277757506040015115159392505050565b6001600160a01b0384166000908152607460209081526040808320868452909152812054819061409990849061408d908763ffffffff6154aa16565b9063ffffffff61550316565b6001600160a01b0387166000908152607460209081526040808320898452909152812060010154919250906140da90859061408d908863ffffffff6154aa16565b6001600160a01b03881660009081526074602090815260408083208a8452909152902054909150600282048301906141129084613b60565b6001600160a01b03891660009081526074602090815260408083208b84529091529020908155600101546141469083613b60565b6001600160a01b03891660009081526074602090815260408083208b84529091529020600101558581106141775750845b979650505050505050565b6001600160a01b038316600090815260726020908152604080832085845282528083208054859003905560689091529020600301546141c7908263ffffffff613b6016565b600083815260686020526040902060030155606c546141ec908263ffffffff613b6016565b606c5560008281526068602052604090205461421957606d54614215908263ffffffff613b6016565b606d555b6000614224836126e8565b905080156142d157614234612f0f565b811015614288576040805162461bcd60e51b815260206004820152601760248201527f696e73756666696369656e742073656c662d7374616b65000000000000000000604482015290519081900360640190fd5b614291836151c6565b6142cc5760405162461bcd60e51b8152600401808060200182810382526029815260200180615b436029913960400191505060405180910390fd5b612ef2565b612ef28360015b6000828152606860205260409020541580156142f357508015155b1561432057600082815260686020526040902060030154606d5461431c9163ffffffff613b6016565b606d555b600082815260686020526040902054811115611ce9576000828152606860205260409020818155600201546143c85761435761290b565b6000838152606860205260409020600201556143716138f3565b6000838152606860209081526040918290206001810184905560020154825190815290810192909252805184927fac4801c32a6067ff757446524ee4e7a373797278ac3c883eac5c693b4ad72e4792908290030190a25b60408051828152905183917fcd35267e7654194727477d6c78b541a553483cff7f92a055d17868d3da6e953e919081900360200190a25050565b670de0b6b3a764000090565b60008215806144245750614420614402565b8210155b1561443157506000614469565b61445c600161172a614441614402565b61408d8661444d614402565b8a91900363ffffffff6154aa16565b9050838111156144695750825b9392505050565b6001600160a01b038816600090815260696020526040902054156144db576040805162461bcd60e51b815260206004820152601860248201527f76616c696461746f7220616c7265616479206578697374730000000000000000604482015290519081900360640190fd5b6001600160a01b03881660008181526069602090815260408083208b90558a8352606882528083208981556004810189905560058101889055600181018690556002810187905560060180547fffffffffffffffffffffffff000000000000000000000000000000000000000016909417909355606a815291902087516145649289019061599d565b50876001600160a01b0316877f49bca1ed2666922f9f1690c26a569e1299c2a715fe57647d77e81adfabbf25bf8686604051808381526020018281526020019250505060405180910390a381156145f0576040805183815260208101839052815189927fac4801c32a6067ff757446524ee4e7a373797278ac3c883eac5c693b4ad72e47928290030190a25b841561462d5760408051868152905188917fcd35267e7654194727477d6c78b541a553483cff7f92a055d17868d3da6e953e919081900360200190a25b5050505050505050565b61463f615931565b614647615931565b61465184846152a5565b6001600160a01b0385166000908152606f6020908152604080832087845282529182902082516060810184528154815260018201549281019290925260020154918101919091529091506127779082615438565b606b80546001019081905561316983828460006146c061290b565b6146c86138f3565b600080614470565b6146da8484611850565b81111561472e576040805162461bcd60e51b815260206004820152601060248201527f6e6f7420656e6f756768207374616b6500000000000000000000000000000000604482015290519081900360640190fd5b6000838152606860205260409020541561478f576040805162461bcd60e51b815260206004820152601660248201527f76616c696461746f722069736e27742061637469766500000000000000000000604482015290519081900360640190fd5b61479761183a565b82101580156147ad57506147a9611831565b8211155b6147fe576040805162461bcd60e51b815260206004820152601260248201527f696e636f7272656374206475726174696f6e0000000000000000000000000000604482015290519081900360640190fd5b600061480c8361172a6138f3565b6000858152606860205260409020600601549091506001600160a01b03908116908616811461489a576001600160a01b038116600090815260736020908152604080832088845290915290206002015482111561489a5760405162461bcd60e51b8152600401808060200182810382526028815260200180615b1b6028913960400191505060405180910390fd5b6148a48686613e86565b506001600160a01b038616600090815260736020908152604080832088845290915290206003810154851015614921576040805162461bcd60e51b815260206004820152601f60248201527f6c6f636b7570206475726174696f6e2063616e6e6f7420646563726561736500604482015290519081900360640190fd5b8054614933908563ffffffff6139fc16565b815561493d61290b565b600182015560028101839055600381018590556040805186815260208101869052815188926001600160a01b038b16927f138940e95abffcd789b497bf6188bba3afa5fbd22fb5c42c2f6018d1bf0f4e78929081900390910190a350505050505050565b600090815260686020526040902060050154151590565b60005b8351811015611613576078548282815181106149d357fe5b60200260200101511180156149fd57506079548382815181106149f257fe5b602002602001015110155b15614a3e57614a20848281518110614a1157fe5b602002602001015160086142d8565b614a3e848281518110614a2f57fe5b60200260200101516000612f35565b828181518110614a4a57fe5b6020026020010151856004016000868481518110614a6457fe5b6020026020010151815260200190815260200160002081905550818181518110614a8a57fe5b6020026020010151856005016000868481518110614aa457fe5b6020908102919091018101518252810191909152604001600020556001016149bb565b614acf615a0b565b6040518060c001604052808551604051908082528060200260200182016040528015614b05578160200160208202803883390190505b508152602001600081526020018551604051908082528060200260200182016040528015614b3d578160200160208202803883390190505b508152602001600081526020016000815260200160008152509050600060776000614b776001614b6b61290b565b9063ffffffff613b6016565b81526020810191909152604001600020600160808401526007810154909150614b9e6138f3565b1115614bb8578060070154614bb16138f3565b0360808301525b60005b8551811015614cc0576000826003016000888481518110614bd857fe5b60200260200101518152602001908152602001600020549050600080905081868481518110614c0357fe5b60200260200101511115614c2a5781868481518110614c1e57fe5b60200260200101510390505b8460800151878481518110614c3b57fe5b6020026020010151820281614c4c57fe5b0485604001518481518110614c5d57fe5b602002602001018181525050614c9785604001518481518110614c7c57fe5b602002602001015186606001516139fc90919063ffffffff16565b606086015260a0850151614cb1908263ffffffff6139fc16565b60a08601525050600101614bbb565b5060005b8551811015614d91578260800151858281518110614cde57fe5b60200260200101518460800151878481518110614cf757fe5b60200260200101518a60000160008b8781518110614d1157fe5b60200260200101518152602001908152602001600020540281614d3057fe5b040281614d3957fe5b0483600001518281518110614d4a57fe5b602002602001018181525050614d8483600001518281518110614d6957fe5b602002602001015184602001516139fc90919063ffffffff16565b6020840152600101614cc4565b5060005b85518110156150e5576000614dcd846080015160755486600001518581518110614dbb57fe5b60200260200101518760200151615545565b9050614e09614dfc8560a0015186604001518581518110614dea57fe5b60200260200101518760600151615586565b829063ffffffff6139fc16565b90506000878381518110614e1957fe5b6020908102919091018101516000818152606890925260408220600601549092506001600160a01b031690614e5584614e50612ce2565b6155e3565b6001600160a01b03831660009081526072602090815260408083208784529091529020549091508015614ffc57600081614e8f85876127a5565b840281614e9857fe5b049050808303614ea6615931565b6001600160a01b03861660009081526073602090815260408083208a8452909152902060030154614ed8908490615600565b9050614ee2615931565b614eed836000615600565b6001600160a01b0388166000908152606f602090815260408083208c84528252918290208251606081018452815481526001820154928101929092526002015491810191909152909150614f429083836156f1565b6001600160a01b0388166000818152606f602090815260408083208d84528252808320855181558583015160018083019190915595820151600291820155938352607482528083208d845282529182902082516060810184528154815294810154918501919091529091015490820152614fbd9083836156f1565b6001600160a01b03881660009081526074602090815260408083208c845282529182902083518155908301516001820155910151600290910155505050505b60008481526068602052604081206003015483870391811561502e5781615021614402565b84028161502a57fe5b0490505b808a600101600089815260200190815260200160002054018f6001016000898152602001908152602001600020819055508b898151811061506b57fe5b60200260200101518f6003016000898152602001908152602001600020819055508c898151811061509857fe5b60200260200101518a600201600089815260200190815260200160002054018f60020160008981526020019081526020016000208190555050505050505050508080600101915050614d95565b505060a081015160088601556020810151600986015560600151600a90940193909355505050565b6001600160a01b0381166151525760405162461bcd60e51b8152600401808060200182810382526026815260200180615a5c6026913960400191505060405180910390fd5b6033546040516001600160a01b038084169216907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3603380547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0392909216919091179055565b60006151f36151d3614402565b61408d6151de611d1f565b6151e7866126e8565b9063ffffffff6154aa16565b60008381526068602052604090206003015411159050919050565b6000818484111561529d5760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b8381101561526257818101518382015260200161524a565b50505050905090810190601f16801561528f5780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b505050900390565b6152ad615931565b6001600160a01b0383166000908152607060209081526040808320858452909152812054906152db846153dd565b905060006152e9868661570c565b9050818111156152f65750805b828110156153015750815b6001600160a01b0386166000818152607360209081526040808320898452825280832093835260728252808320898452909152812054825490919061534d90839063ffffffff613b6016565b9050600061536184600001548a89886157e9565b905061536b615931565b615379828660030154615600565b9050615387838b8a896157e9565b9150615391615931565b61539c836000615600565b90506153aa858c898b6157e9565b92506153b4615931565b6153bf846000615600565b90506153cc8383836156f1565b9d9c50505050505050505050505050565b600081815260686020526040812060020154156154305760008281526068602052604090206002015460675410156154185750606754612719565b50600081815260686020526040902060020154612719565b505060675490565b615440615931565b6040805160608101909152825184518291615461919063ffffffff6139fc16565b8152602001615481846020015186602001516139fc90919063ffffffff16565b81526020016154a1846040015186604001516139fc90919063ffffffff16565b90529392505050565b6000826154b9575060006118d3565b828202828482816154c657fe5b04146118d05760405162461bcd60e51b8152600401808060200182810382526021815260200180615aab6021913960400191505060405180910390fd5b60006118d083836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f00000000000081525061584c565b60008261555457506000612777565b6000615566868663ffffffff6154aa16565b905061557c8361408d838763ffffffff6154aa16565b9695505050505050565b60008261559557506000614469565b60006155ab8361408d878763ffffffff6154aa16565b90506155da6155b8614402565b61408d6155c3611d31565b6155cb614402565b8591900363ffffffff6154aa16565b95945050505050565b60006118d06155f0614402565b61408d858563ffffffff6154aa16565b615608615931565b6040518060600160405280600081526020016000815260200160008152509050816000146156c357600061563a611d31565b615642614402565b0390506000615662615652611831565b61408d848763ffffffff6154aa16565b9050600061568b615671614402565b61408d8461567d611d31565b8a910163ffffffff6154aa16565b90506156b0615698614402565b61408d6156a3611d31565b899063ffffffff6154aa16565b6020850181905290038352506118d39050565b6156e66156ce614402565b61408d6156d9611d31565b869063ffffffff6154aa16565b604082015292915050565b6156f9615931565b6127776157068585615438565b83615438565b6001600160a01b03821660009081526073602090815260408083208484529091528120600101546067546157418585836158b1565b1561574f5791506118d39050565b61575a8585846158b1565b615769576000925050506118d3565b8082111561577c576000925050506118d3565b808210156157af576002818301046157958686836158b1565b156157a5578060010192506157a9565b8091505b5061577c565b806157bf576000925050506118d3565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01949350505050565b60008183106157fa57506000612777565b600083815260776020818152604080842088855260019081018352818520548786529383528185208986520190915290912054614177615838614402565b61408d896151e7858763ffffffff613b6016565b6000818361589b5760405162461bcd60e51b815260206004820181815283516024840152835190928392604490910191908501908083836000831561526257818101518382015260200161524a565b5060008385816158a757fe5b0495945050505050565b6001600160a01b0383166000908152607360209081526040808320858452909152812060010154821080159061277757506001600160a01b03841660009081526073602090815260408083208684529091529020600201546159128361591c565b1115949350505050565b60009081526077602052604090206007015490565b60405180606001604052806000815260200160008152602001600081525090565b82805482825590600052602060002090810192821561598d579160200282015b8281111561598d578235825591602001919060010190615972565b50615999929150615a41565b5090565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106159de57805160ff191683800117855561598d565b8280016001018555821561598d579182015b8281111561598d5782518255916020019190600101906159f0565b6040518060c001604052806060815260200160008152602001606081526020016000815260200160008152602001600081525090565b61183791905b808211156159995760008155600101615a4756fe4f776e61626c653a206e6577206f776e657220697320746865207a65726f206164647265737363616c6c6572206973206e6f7420746865204e6f64654472697665724175746820636f6e7472616374536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f77436f6e747261637420696e7374616e63652068617320616c7265616479206265656e20696e697469616c697a65646d757374206265206c657373207468616e206f7220657175616c20746f20312e3076616c696461746f72206c6f636b757020706572696f642077696c6c20656e64206561726c69657276616c696461746f7227732064656c65676174696f6e73206c696d69742069732065786365656465646c6f636b6564207374616b652069732067726561746572207468616e207468652077686f6c65207374616b65a265627a7a723158201e2c0c2613e9f5b1b982f1d341fd2892182615eda299d96c66dad0b19a60772564736f6c63430005110032
Age | Block | Fee Address | BC Fee Address | Voting Power | Jailed | Incoming |
---|
Validator ID :
0 FTM
Amount Staked
0
Amount Delegated
0
Staking Total
0
Staking Start Epoch
0
Staking Start Time
0
Proof of Importance
0
Origination Score
0
Validation Score
0
Active
0
Online
0
Downtime
0 s
Address | Amount | claimed Rewards | Created On Epoch | Created On |
---|
Make sure to use the "Vote Down" button for any spammy posts, and the "Vote Up" for interesting conversations.