false
true
0

Contract Address Details

0x72C3924E7f603ce9BAa7D85ca25aF28151350FC7

Token
Degen God (DEGENG)
Creator
0x6c12fd–ad5d11 at 0x72e678–183356
Balance
0 PLS ( )
Tokens
Fetching tokens...
Transactions
630 Transactions
Transfers
0 Transfers
Gas Used
0
Last Balance Update
26124795
Warning! Contract bytecode has been changed and doesn't match the verified one. Therefore, interaction with this smart contract may be risky.
Contract name:
DegenGod




Optimization enabled
true
Compiler version
v0.5.13+commit.5b0b510c




Optimization runs
200
EVM Version
default




Verified at
2023-12-06T18:13:30.597524Z

Contract source code

pragma solidity 0.5.13;

/*
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with GSN meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */

contract Context {
    // Empty internal constructor, to prevent people from mistakenly deploying
    // an instance of this contract, which should be used via inheritance.
    constructor () internal { }
    // solhint-disable-previous-line no-empty-blocks

    function _msgSender() internal view returns (address payable) {
        return msg.sender;
    }

    function _msgData() internal view returns (bytes memory) {
        this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
        return msg.data;
    }
}

/**
 * @dev Interface of the ERC20 standard as defined in the EIP. Does not include
 * the optional functions; to access them see {ERC20Detailed}.
 */

interface IERC20 {
    /**
     * @dev Returns the amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns the amount of tokens owned by `account`.
     */
    function balanceOf(address account) external view returns (uint256);

    /**
     * @dev Moves `amount` tokens from the caller's account to `recipient`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address recipient, uint256 amount) external returns (bool);

    /**
     * @dev Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through {transferFrom}. This is
     * zero by default.
     *
     * This value changes when {approve} or {transferFrom} are called.
     */
    function allowance(address owner, address spender) external view returns (uint256);

    /**
     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * IMPORTANT: Beware that changing an allowance with this method brings the risk
     * that someone may use both the old and the new allowance by unfortunate
     * transaction ordering. One possible solution to mitigate this race
     * condition is to first reduce the spender's allowance to 0 and set the
     * desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * Emits an {Approval} event.
     */
    function approve(address spender, uint256 amount) external returns (bool);

    /**
     * @dev Moves `amount` tokens from `sender` to `recipient` using the
     * allowance mechanism. `amount` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);

    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

    /**
     * @dev Emitted when the allowance of a `spender` for an `owner` is set by
     * a call to {approve}. `value` is the new allowance.
     */
    event Approval(address indexed owner, address indexed spender, uint256 value);
}

/**
 * @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;
    }
}

/**
 * @dev Implementation of the {IERC20} interface.
 *
 * This implementation is agnostic to the way tokens are created. This means
 * that a supply mechanism has to be added in a derived contract using {_mint}.
 * For a generic mechanism see {ERC20Mintable}.
 *
 * TIP: For a detailed writeup see our guide
 * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How
 * to implement supply mechanisms].
 *
 * We have followed general OpenZeppelin guidelines: functions revert instead
 * of returning `false` on failure. This behavior is nonetheless conventional
 * and does not conflict with the expectations of ERC20 applications.
 *
 * Additionally, an {Approval} event is emitted on calls to {transferFrom}.
 * This allows applications to reconstruct the allowance for all accounts just
 * by listening to said events. Other implementations of the EIP may not emit
 * these events, as it isn't required by the specification.
 *
 * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}
 * functions have been added to mitigate the well-known issues around setting
 * allowances. See {IERC20-approve}.
 */

contract ERC20 is Context, IERC20 {
    using SafeMath for uint256;

    mapping (address => uint256) private _balances;
    mapping (address => mapping (address => uint256)) private _allowances;
    mapping (address => bool) public isBlacklisted;

//    bool public buyCooldownEnabled          = true;
//    uint8 public cooldownTimerInterval      = 15;
//    mapping (address => uint) private cooldownTimer;

    uint256 private _totalSupply;

    /**
     * @dev See {IERC20-totalSupply}.
     */
    function totalSupply() public view returns (uint256) {
        return _totalSupply;
    }

    /**
     * @dev See {IERC20-balanceOf}.
     */
    function balanceOf(address account) public view returns (uint256) {
        return _balances[account];
    }

    /**
     * @dev See {IERC20-transfer}.
     *
     * Requirements:
     *
     * - `recipient` cannot be the zero address.
     * - the caller must have a balance of at least `amount`.
     */
    function transfer(address recipient, uint256 amount) public returns (bool) {
        _transfer(_msgSender(), recipient, amount);
        return true;
    }

    /**
     * @dev See {IERC20-allowance}.
     */
    function allowance(address owner, address spender) public view returns (uint256) {
        return _allowances[owner][spender];
    }

    /**
     * @dev See {IERC20-approve}.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     */
    function approve(address spender, uint256 amount) public returns (bool) {
        _approve(_msgSender(), spender, amount);
        return true;
    }

    /**
     * @dev See {IERC20-transferFrom}.
     *
     * Emits an {Approval} event indicating the updated allowance. This is not
     * required by the EIP. See the note at the beginning of {ERC20};
     *
     * Requirements:
     * - `sender` and `recipient` cannot be the zero address.
     * - `sender` must have a balance of at least `amount`.
     * - the caller must have allowance for `sender`'s tokens of at least
     * `amount`.
     */
    function transferFrom(address sender, address recipient, uint256 amount) public returns (bool) {
        _transfer(sender, recipient, amount);
        _approve(sender, _msgSender(), _allowances[sender][_msgSender()].sub(amount, "ERC20: transfer amount exceeds allowance"));
        return true;
    }

    /**
     * @dev Atomically increases the allowance granted to `spender` by the caller.
     *
     * This is an alternative to {approve} that can be used as a mitigation for
     * problems described in {IERC20-approve}.
     *
     * Emits an {Approval} event indicating the updated allowance.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     */
    function increaseAllowance(address spender, uint256 addedValue) public returns (bool) {
        _approve(_msgSender(), spender, _allowances[_msgSender()][spender].add(addedValue));
        return true;
    }

    /**
     * @dev Atomically decreases the allowance granted to `spender` by the caller.
     *
     * This is an alternative to {approve} that can be used as a mitigation for
     * problems described in {IERC20-approve}.
     *
     * Emits an {Approval} event indicating the updated allowance.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     * - `spender` must have allowance for the caller of at least
     * `subtractedValue`.
     */
    function decreaseAllowance(address spender, uint256 subtractedValue) public returns (bool) {
        _approve(_msgSender(), spender, _allowances[_msgSender()][spender].sub(subtractedValue, "ERC20: decreased allowance below zero"));
        return true;
    }

    /**
     * @dev Moves tokens `amount` from `sender` to `recipient`.
     *
     * This is internal function is equivalent to {transfer}, and can be used to
     * e.g. implement automatic token fees, slashing mechanisms, etc.
     *
     * Emits a {Transfer} event.
     *
     * Requirements:
     *
     * - `sender` cannot be the zero address.
     * - `recipient` cannot be the zero address.
     * - `sender` must have a balance of at least `amount`.
     */

    //TODO to limit buys this is the function to add that functionality to
    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");
        require(!isBlacklisted[recipient] && !isBlacklisted[sender], 'Address is blacklisted');

        _balances[sender] = _balances[sender].sub(amount, "ERC20: transfer amount exceeds balance");
        _balances[recipient] = _balances[recipient].add(amount);
        emit Transfer(sender, recipient, amount);
    }

    /** @dev Creates `amount` tokens and assigns them to `account`, increasing
     * the total supply.
     *
     * Emits a {Transfer} event with `from` set to the zero address.
     *
     * Requirements
     *
     * - `to` cannot be the zero address.
     */
    function _mint(address account, uint256 amount) internal {
        require(account != address(0), "ERC20: mint to the zero address");

        _totalSupply = _totalSupply.add(amount);
        _balances[account] = _balances[account].add(amount);
        emit Transfer(address(0), account, amount);
    }
     /**
     * @dev Destroys `amount` tokens from `account`, reducing the
     * total supply.
     *
     * Emits a {Transfer} event with `to` set to the zero address.
     *
     * Requirements
     *
     * - `account` cannot be the zero address.
     * - `account` must have at least `amount` tokens.
     */
    function _burn(address account, uint256 amount) internal {
        require(account != address(0), "ERC20: burn from the zero address");

        _balances[account] = _balances[account].sub(amount, "ERC20: burn amount exceeds balance");
        _totalSupply = _totalSupply.sub(amount);
        emit Transfer(account, address(0), amount);
    }

    /**
     * @dev Sets `amount` as the allowance of `spender` over the `owner`s tokens.
     *
     * This is internal function is equivalent to `approve`, and can be used to
     * e.g. set automatic allowances for certain subsystems, etc.
     *
     * Emits an {Approval} event.
     *
     * Requirements:
     *
     * - `owner` cannot be the zero address.
     * - `spender` cannot be the zero address.
     */
    function _approve(address owner, address spender, uint256 amount) internal {
        require(owner != address(0), "ERC20: approve from the zero address");
        require(spender != address(0), "ERC20: approve to the zero address");

        _allowances[owner][spender] = amount;
        emit Approval(owner, spender, amount);
    }

    /**
     * @dev Destroys `amount` tokens from `account`.`amount` is then deducted
     * from the caller's allowance.
     *
     * See {_burn} and {_approve}.
     */
    function _burnFrom(address account, uint256 amount) internal {
        _burn(account, amount);
        _approve(account, _msgSender(), _allowances[account][_msgSender()].sub(amount, "ERC20: burn amount exceeds allowance"));
    }
}

contract GlobalsAndUtility is ERC20 {

    /*  DailyDataUpdate   (auto-generated event)

        uint40            timestamp       -->  data0 [ 39:  0]
        uint16            beginDay        -->  data0 [ 55: 40]
        uint16            endDay          -->  data0 [ 71: 56]
        bool              isAutoUpdate    -->  data0 [ 79: 72]
        address  indexed  updaterAddr
    */
    event DailyDataUpdate(
        uint256 data0,
        address indexed updaterAddr
    );

    /*  StakeStart        (auto-generated event)

        uint40            timestamp       -->  data0 [ 39:  0]
        address  indexed  stakerAddr
        uint40   indexed  stakeId
        uint72            stakedHearts    -->  data0 [111: 40]
        uint72            stakeShares     -->  data0 [183:112]
        uint16            stakedDays      -->  data0 [199:184]
        bool              isAutoStake     -->  data0 [207:200]
    */
    event StakeStart(
        uint256 data0,
        address indexed stakerAddr,
        uint40 indexed stakeId
    );

    /*  StakeGoodAccounting(auto-generated event)

        uint40            timestamp       -->  data0 [ 39:  0]
        address  indexed  stakerAddr
        uint40   indexed  stakeId
        uint72            stakedHearts    -->  data0 [111: 40]
        uint72            stakeShares     -->  data0 [183:112]
        uint72            payout          -->  data0 [255:184]
        uint72            penalty         -->  data1 [ 71:  0]
        address  indexed  senderAddr
    */
    event StakeGoodAccounting(
        uint256 data0,
        uint256 data1,
        address indexed stakerAddr,
        uint40 indexed stakeId,
        address indexed senderAddr
    );

    /*  StakeEnd          (auto-generated event)

        uint40            timestamp       -->  data0 [ 39:  0]
        address  indexed  stakerAddr
        uint40   indexed  stakeId
        uint72            stakedHearts    -->  data0 [111: 40]
        uint72            stakeShares     -->  data0 [183:112]
        uint72            payout          -->  data0 [255:184]
        uint72            penalty         -->  data1 [ 71:  0]
        uint16            servedDays      -->  data1 [ 87: 72]
        bool              prevUnlocked    -->  data1 [ 95: 88]
    */
    event StakeEnd(
        uint256 data0,
        uint256 data1,
        address indexed stakerAddr,
        uint40 indexed stakeId
    );

    /*  ShareRateChange   (auto-generated event)

        uint40            timestamp       -->  data0 [ 39:  0]
        uint40            shareRate       -->  data0 [ 79: 40]
        uint40   indexed  stakeId
    */
    event ShareRateChange(
        uint256 data0,
        uint40 indexed stakeId
    );

    /* Origin address */
    address public constant ORIGIN_ADDR = address(0x000000000000000000000000000000000000dEaD); //this is a real burn address, no way to recover the tokens

    /* ERC20 constants */
    string public constant name = "Degen God";
    string public constant symbol = "DEGENG";
    uint8 public constant decimals = 8;

    /* Hearts per Satoshi = 10,000 * 1e8 / 1e8 = 1e4 */
    uint256 private constant HEARTS_PER_HEX = 10 ** uint256(decimals); // 1e8
    uint256 private constant HEX_PER_BTC = 1e4;

    uint256 internal LAUNCH_TIME;

    /* Size of a Hearts or Shares uint */
    uint256 internal constant HEART_UINT_SIZE = 72;

    /* Start of claim phase */
    uint256 internal constant PRE_CLAIM_DAYS = 1;
    uint256 internal constant CLAIM_PHASE_START_DAY = PRE_CLAIM_DAYS;

    /* Stake timing parameters */
    uint256 internal constant MIN_STAKE_DAYS = 1;
    uint256 internal constant MIN_AUTO_STAKE_DAYS = 350;

    uint256 internal constant MAX_STAKE_DAYS = 5555; // Approx 15 years

    uint256 internal constant EARLY_PENALTY_MIN_DAYS = 90;

    uint256 private constant LATE_PENALTY_GRACE_WEEKS = 2;
    uint256 internal constant LATE_PENALTY_GRACE_DAYS = LATE_PENALTY_GRACE_WEEKS * 7;

    uint256 private constant LATE_PENALTY_SCALE_WEEKS = 100;
    uint256 internal constant LATE_PENALTY_SCALE_DAYS = LATE_PENALTY_SCALE_WEEKS * 7;

    /* Stake shares Longer Pays Better bonus constants used by _stakeStartBonusHearts() */
    uint256 private constant LPB_BONUS_PERCENT = 20;
    uint256 private constant LPB_BONUS_MAX_PERCENT = 200;
    uint256 internal constant LPB = 364 * 100 / LPB_BONUS_PERCENT;
    uint256 internal constant LPB_MAX_DAYS = LPB * LPB_BONUS_MAX_PERCENT / 100;

    /* Stake shares Bigger Pays Better bonus constants used by _stakeStartBonusHearts() */
    uint256 private constant BPB_BONUS_PERCENT = 10;
    uint256 private constant BPB_MAX_HEX = 150 * 1e6;
    uint256 internal constant BPB_MAX_HEARTS = BPB_MAX_HEX * HEARTS_PER_HEX;
    uint256 internal constant BPB = BPB_MAX_HEARTS * 100 / BPB_BONUS_PERCENT;

    /* Share rate is scaled to increase precision */
    uint256 internal constant SHARE_RATE_SCALE = 1e5;

    /* Share rate max (after scaling) */
    uint256 internal constant SHARE_RATE_UINT_SIZE = 40;
    uint256 internal constant SHARE_RATE_MAX = (1 << SHARE_RATE_UINT_SIZE) - 1;

    /* Globals expanded for memory (except _latestStakeId) and compact for storage */
    struct GlobalsCache {
        // 1
        uint256 _lockedHeartsTotal;
        uint256 _nextStakeSharesTotal;
        uint256 _shareRate;
        uint256 _stakePenaltyTotal;
        // 2
        uint256 _dailyDataCount;
        uint256 _stakeSharesTotal;
        uint40 _latestStakeId;
        //
        uint256 _currentDay;
    }

    struct GlobalsStore {
        // 1
        uint72 lockedHeartsTotal;
        uint72 nextStakeSharesTotal;
        uint40 shareRate;
        uint72 stakePenaltyTotal;
        // 2
        uint16 dailyDataCount;
        uint72 stakeSharesTotal;
        uint40 latestStakeId;
    }

    GlobalsStore public globals;

    /* Daily data */
    struct DailyDataStore {
        uint72 dayPayoutTotal;
        uint72 dayStakeSharesTotal;
        //TODO remove this variable in the future - study how the encoding mechanism is working
        uint56 dayUnclaimedSatoshisTotal;
    }

    mapping(uint256 => DailyDataStore) public dailyData;

    /* Stake expanded for memory (except _stakeId) and compact for storage */
    struct StakeCache {
        uint40 _stakeId;
        uint256 _stakedHearts;
        uint256 _stakeShares;
        uint256 _lockedDay;
        uint256 _stakedDays;
        uint256 _unlockedDay;
        bool _isAutoStake;
    }

    struct StakeStore {
        uint40 stakeId;
        uint72 stakedHearts;
        uint72 stakeShares;
        uint16 lockedDay;
        uint16 stakedDays;
        uint16 unlockedDay;
        bool isAutoStake;
    }

    mapping(address => StakeStore[]) public stakeLists;

    /* Temporary state for calculating daily rounds */
    struct DailyRoundState {
        uint256 _allocSupplyCached;
        uint256 _mintOriginBatch;
        uint256 _payoutTotal;
    }

    mapping(address => mapping(address => mapping(uint40 => bool))) public approvedStakesForMoving;

    /**
     * @dev PUBLIC FACING: Optionally update daily data for a smaller
     * range to reduce gas cost for a subsequent operation
     * @param beforeDay Only update days before this day number (optional; 0 for current day)
     */
    function dailyDataUpdate(uint256 beforeDay)
        external
    {
        GlobalsCache memory g;
        GlobalsCache memory gSnapshot;
        _globalsLoad(g, gSnapshot);

        /* Skip pre-claim period */
        require(g._currentDay > CLAIM_PHASE_START_DAY, "DEGENG: Too early");

        if (beforeDay != 0) {
            require(beforeDay <= g._currentDay, "DEGENG: beforeDay cannot be in the future");

            _dailyDataUpdate(g, beforeDay, false);
        } else {
            /* Default to updating before current day */
            _dailyDataUpdate(g, g._currentDay, false);
        }

        _globalsSync(g, gSnapshot);
    }

    /**
     * @dev PUBLIC FACING: External helper to return multiple values of daily data with
     * a single call. Ugly implementation due to limitations of the standard ABI encoder.
     * @param beginDay First day of data range
     * @param endDay Last day (non-inclusive) of data range
     * @return Fixed array of packed values
     */
    function dailyDataRange(uint256 beginDay, uint256 endDay)
        external
        view
        returns (uint256[] memory list)
    {
        require(beginDay < endDay && endDay <= globals.dailyDataCount, "DEGENG: range invalid");

        list = new uint256[](endDay - beginDay);

        uint256 src = beginDay;
        uint256 dst = 0;
        uint256 v;
        do {
            v = uint256(dailyData[src].dayUnclaimedSatoshisTotal) << (HEART_UINT_SIZE * 2);
            v |= uint256(dailyData[src].dayStakeSharesTotal) << HEART_UINT_SIZE;
            v |= uint256(dailyData[src].dayPayoutTotal);

            list[dst++] = v;
        } while (++src < endDay);

        return list;
    }

    /**
     * @dev PUBLIC FACING: External helper to return most global info with a single call.
     * Ugly implementation due to limitations of the standard ABI encoder.
     * @return Fixed array of values
     */
    function globalInfo()
        external
        view
        returns (uint256[9] memory)
    {

        return [
            // 1
            globals.lockedHeartsTotal,
            globals.nextStakeSharesTotal,
            globals.shareRate,
            globals.stakePenaltyTotal,
            // 2
            globals.dailyDataCount,
            globals.stakeSharesTotal,
            globals.latestStakeId,
            //
            block.timestamp,
            totalSupply()
        ];
    }

    /**
     * @dev PUBLIC FACING: ERC20 totalSupply() is the circulating supply and does not include any
     * staked Hearts. allocatedSupply() includes both.
     * @return Allocated Supply in Hearts
     */
    function allocatedSupply()
        external
        view
        returns (uint256)
    {
        return totalSupply() + globals.lockedHeartsTotal;
    }

    //uncomment this function for production!
    function elapsedTimeSinceLaunch() external view returns (uint256) {
        return (block.timestamp - LAUNCH_TIME);
    }

    /**
     * @dev PUBLIC FACING: External helper for the current day number since launch time
     * @return Current day number (zero-based)
     */
    function currentDay()
        external
        view
        returns (uint256)
    {
        return _currentDay();
    }

    function _currentDay()
        internal
        view
        returns (uint256)
    {
        return (block.timestamp - LAUNCH_TIME) / 1 days;
    }

    function _dailyDataUpdateAuto(GlobalsCache memory g)
        internal
    {
        _dailyDataUpdate(g, g._currentDay, true);
    }

    function _globalsLoad(GlobalsCache memory g, GlobalsCache memory gSnapshot)
        internal
        view
    {
        // 1
        g._lockedHeartsTotal = globals.lockedHeartsTotal;
        g._nextStakeSharesTotal = globals.nextStakeSharesTotal;
        g._shareRate = globals.shareRate;
        g._stakePenaltyTotal = globals.stakePenaltyTotal;
        // 2
        g._dailyDataCount = globals.dailyDataCount;
        g._stakeSharesTotal = globals.stakeSharesTotal;
        g._latestStakeId = globals.latestStakeId;
        //
        g._currentDay = _currentDay();

        _globalsCacheSnapshot(g, gSnapshot);
    }

    function _globalsCacheSnapshot(GlobalsCache memory g, GlobalsCache memory gSnapshot)
        internal
        pure
    {
        // 1
        gSnapshot._lockedHeartsTotal = g._lockedHeartsTotal;
        gSnapshot._nextStakeSharesTotal = g._nextStakeSharesTotal;
        gSnapshot._shareRate = g._shareRate;
        gSnapshot._stakePenaltyTotal = g._stakePenaltyTotal;
        // 2
        gSnapshot._dailyDataCount = g._dailyDataCount;
        gSnapshot._stakeSharesTotal = g._stakeSharesTotal;
        gSnapshot._latestStakeId = g._latestStakeId;
    }

    function _globalsSync(GlobalsCache memory g, GlobalsCache memory gSnapshot)
        internal
    {
        if (g._lockedHeartsTotal != gSnapshot._lockedHeartsTotal
            || g._nextStakeSharesTotal != gSnapshot._nextStakeSharesTotal
            || g._shareRate != gSnapshot._shareRate
            || g._stakePenaltyTotal != gSnapshot._stakePenaltyTotal) {
            // 1
            globals.lockedHeartsTotal = uint72(g._lockedHeartsTotal);
            globals.nextStakeSharesTotal = uint72(g._nextStakeSharesTotal);
            globals.shareRate = uint40(g._shareRate);
            globals.stakePenaltyTotal = uint72(g._stakePenaltyTotal);
        }
        if (g._dailyDataCount != gSnapshot._dailyDataCount
            || g._stakeSharesTotal != gSnapshot._stakeSharesTotal
            || g._latestStakeId != gSnapshot._latestStakeId) {
            // 2
            globals.dailyDataCount = uint16(g._dailyDataCount);
            globals.stakeSharesTotal = uint72(g._stakeSharesTotal);
            globals.latestStakeId = g._latestStakeId;
        }
    }

    function _stakeLoad(StakeStore storage stRef, uint40 stakeIdParam, StakeCache memory st)
        internal
        view
    {
        /* Ensure caller's stakeIndex is still current */
        require(stakeIdParam == stRef.stakeId, "DEGENG: stakeIdParam not in stake");

        st._stakeId = stRef.stakeId;
        st._stakedHearts = stRef.stakedHearts;
        st._stakeShares = stRef.stakeShares;
        st._lockedDay = stRef.lockedDay;
        st._stakedDays = stRef.stakedDays;
        st._unlockedDay = stRef.unlockedDay;
        st._isAutoStake = stRef.isAutoStake;
    }

    function _stakeUpdate(StakeStore storage stRef, StakeCache memory st)
        internal
    {
        stRef.stakeId = st._stakeId;
        stRef.stakedHearts = uint72(st._stakedHearts);
        stRef.stakeShares = uint72(st._stakeShares);
        stRef.lockedDay = uint16(st._lockedDay);
        stRef.stakedDays = uint16(st._stakedDays);
        stRef.unlockedDay = uint16(st._unlockedDay);
        stRef.isAutoStake = st._isAutoStake;
    }

    function _stakeAdd(
        StakeStore[] storage stakeListRef,
        uint40 newStakeId,
        uint256 newStakedHearts,
        uint256 newStakeShares,
        uint256 newLockedDay,
        uint256 newStakedDays,
        bool newAutoStake
    )
        internal
    {
        stakeListRef.push(
            StakeStore(
                newStakeId,
                uint72(newStakedHearts),
                uint72(newStakeShares),
                uint16(newLockedDay),
                uint16(newStakedDays),
                uint16(0), // unlockedDay
                newAutoStake
            )
        );
    }

    /**
     * @dev Efficiently delete from an unordered array by moving the last element
     * to the "hole" and reducing the array length. Can change the order of the list
     * and invalidate previously held indexes.
     * @notice stakeListRef length and stakeIndex are already ensured valid in stakeEnd()
     * @param stakeListRef Reference to stakeLists[stakerAddr] array in storage
     * @param stakeIndex Index of the element to delete
     */
    function _stakeRemove(StakeStore[] storage stakeListRef, uint256 stakeIndex)
        internal
    {
        uint256 lastIndex = stakeListRef.length - 1;

        /* Skip the copy if element to be removed is already the last element */
        if (stakeIndex != lastIndex) {
            /* Copy last element to the requested element's "hole" */
            stakeListRef[stakeIndex] = stakeListRef[lastIndex];
        }

        /*
            Reduce the array length now that the array is contiguous.
            Surprisingly, 'pop()' uses less gas than 'stakeListRef.length = lastIndex'
        */
        stakeListRef.pop();
    }
    
    /**
     * @dev Estimate the stake payout for an incomplete day
     * @param g Cache of stored globals
     * @param stakeSharesParam Param from stake to calculate bonuses for
     * @return Payout in Hearts
     */
    function _estimatePayoutRewardsDay(GlobalsCache memory g, uint256 stakeSharesParam)
        internal
        view
        returns (uint256 payout)
    {
        /* Prevent updating state for this estimation */
        GlobalsCache memory gTmp;
        _globalsCacheSnapshot(g, gTmp);

        DailyRoundState memory rs;
        rs._allocSupplyCached = totalSupply() + g._lockedHeartsTotal;

        _dailyRoundCalc(gTmp, rs);

        /* Stake is no longer locked so it must be added to total as if it were */
        gTmp._stakeSharesTotal += stakeSharesParam;

        payout = rs._payoutTotal * stakeSharesParam / gTmp._stakeSharesTotal;

        return payout;
    }

    function _dailyRoundCalc(GlobalsCache memory g, DailyRoundState memory rs)
        private
        pure
    {
        /*  HEX Method
            Calculate payout round

            Inflation of 3.69% inflation per 364 days             (approx 1 year)
            dailyInterestRate   = exp(log(1 + 3.69%)  / 364) - 1
                                = exp(log(1 + 0.0369) / 364) - 1
                                = exp(log(1.0369) / 364) - 1
                                = 0.000099553011616349            (approx)

            payout  = allocSupply * dailyInterestRate
                    = allocSupply / (1 / dailyInterestRate)
                    = allocSupply / (1 / 0.000099553011616349)
                    = allocSupply / 10044.899534066692            (approx)
                    = allocSupply * 10000 / 100448995             (* 10000/10000 for int precision)
        */
        /*  DEGENG Method for 69% APY
            Calculate payout round

            Inflation of 69% inflation per 364 days             (approx 1 year)
            dailyInterestRate   = exp(log(1 + 69%)  / 364) - 1
                                = exp(log(1 + 0.69) / 364) - 1
                                = exp(log(1.69) / 364) - 1
                                = 0.001442601442489               (approx)

            payout  = allocSupply * dailyInterestRate
                    = allocSupply / (1 / dailyInterestRate)
                    = allocSupply / (1 / 0.001442601442489)
                    = allocSupply / 693.192153111011            (approx)
                    = allocSupply * 10000 / 6931921             (* 10000/10000 for int precision)
        */
        rs._payoutTotal = rs._allocSupplyCached * 10000 / 6931921;

        if (g._stakePenaltyTotal != 0) {
            rs._payoutTotal += g._stakePenaltyTotal;
            g._stakePenaltyTotal = 0;
        }
    }

    function _dailyRoundCalcAndStore(GlobalsCache memory g, DailyRoundState memory rs, uint256 day)
        private
    {
        _dailyRoundCalc(g, rs);

        dailyData[day].dayPayoutTotal = uint72(rs._payoutTotal);
        dailyData[day].dayStakeSharesTotal = uint72(g._stakeSharesTotal);
    }

    function _dailyDataUpdate(GlobalsCache memory g, uint256 beforeDay, bool isAutoUpdate)
        private
    {
        _dailyDataUpdateAux(msg.sender, g, beforeDay, isAutoUpdate);
    }

    function _dailyDataUpdateAux(address account, GlobalsCache memory g, uint256 beforeDay, bool isAutoUpdate)
        internal
    {
        if (g._dailyDataCount >= beforeDay) {
            /* Already up-to-date */
            return;
        }

        DailyRoundState memory rs;
        rs._allocSupplyCached = totalSupply() + g._lockedHeartsTotal;

        uint256 day = g._dailyDataCount;

        _dailyRoundCalcAndStore(g, rs, day);

        /* Stakes started during this day are added to the total the next day */
        if (g._nextStakeSharesTotal != 0) {
            g._stakeSharesTotal += g._nextStakeSharesTotal;
            g._nextStakeSharesTotal = 0;
        }

        while (++day < beforeDay) {
            _dailyRoundCalcAndStore(g, rs, day);
        }

        _emitDailyDataUpdate(account, g._dailyDataCount, day, isAutoUpdate);
        g._dailyDataCount = day;

        if (rs._mintOriginBatch != 0) {
            _mint(ORIGIN_ADDR, rs._mintOriginBatch);
        }
    }

    function _emitDailyDataUpdate(address account, uint256 beginDay, uint256 endDay, bool isAutoUpdate)
        private
    {
        emit DailyDataUpdate( // (auto-generated event)
            uint256(uint40(block.timestamp))
                | (uint256(uint16(beginDay)) << 40)
                | (uint256(uint16(endDay)) << 56)
                | (isAutoUpdate ? (1 << 72) : 0),
            account
        );
    }
}

contract StakeableToken is GlobalsAndUtility {
    
    function stake(uint256 newStakedHearts, uint256 newStakedDays) external {
        _stake(msg.sender, newStakedHearts, newStakedDays);
    }
    
    /**
     * @dev Open a stake.
     * @param newStakedHearts Number of Hearts to stake
     * @param newStakedDays Number of days to stake
     */
    function _stake(address account, uint256 newStakedHearts, uint256 newStakedDays)
        internal
    {
        GlobalsCache memory g;
        GlobalsCache memory gSnapshot;
        _globalsLoad(g, gSnapshot);

        /* Enforce the minimum stake time */
        require(newStakedDays >= MIN_STAKE_DAYS, "DEGENG: newStakedDays lower than minimum");

        /* Check if log data needs to be updated */
         _dailyDataUpdateAux(account, g, g._currentDay, true);

        _stakeStart(account, g, newStakedHearts, newStakedDays, false);

        /* Remove staked Hearts from balance of staker */
        _burn(account, newStakedHearts);

        _globalsSync(g, gSnapshot);
    }

    /**
     * @dev PUBLIC FACING: Unlocks a completed stake, distributing the proceeds of any penalty
     * immediately. The staker must still call stakeEnd() to retrieve their stake return (if any).
     * @param stakerAddr Address of staker
     * @param stakeIndex Index of stake within stake list
     * @param stakeIdParam The stake's id
     */

    function stakeGoodAccounting(address stakerAddr, uint256 stakeIndex, uint40 stakeIdParam)
        external
    {
        GlobalsCache memory g;
        GlobalsCache memory gSnapshot;
        _globalsLoad(g, gSnapshot);

        /* require() is more informative than the default assert() */
        require(stakeLists[stakerAddr].length != 0, "DEGENG: Empty stake list");
        require(stakeIndex < stakeLists[stakerAddr].length, "DEGENG: stakeIndex invalid");

        StakeStore storage stRef = stakeLists[stakerAddr][stakeIndex];

        /* Get stake copy */
        StakeCache memory st;
        _stakeLoad(stRef, stakeIdParam, st);

        /* Stake must have served full term */
        require(g._currentDay >= st._lockedDay + st._stakedDays, "DEGENG: Stake not fully served");

        /* Stake must still be locked */
        require(st._unlockedDay == 0, "DEGENG: Stake already unlocked");

        /* Check if log data needs to be updated */
        _dailyDataUpdateAuto(g);

        /* Unlock the completed stake */
        _stakeUnlock(g, st);

        /* stakeReturn value is unused here */
        (, uint256 payout, uint256 penalty, uint256 cappedPenalty) = _stakePerformance(
            g,
            st,
            st._stakedDays
        );

        _emitStakeGoodAccounting(
            stakerAddr,
            stakeIdParam,
            st._stakedHearts,
            st._stakeShares,
            payout,
            penalty
        );

        if (cappedPenalty != 0) {
            _splitPenaltyProceeds(g, cappedPenalty);
        }

        /* st._unlockedDay has changed */
        _stakeUpdate(stRef, st);

        _globalsSync(g, gSnapshot);
    }

    /**
     * @dev PUBLIC FACING: Closes a stake. The order of the stake list can change so
     * a stake id is used to reject stale indexes.
     * @param stakeIndex Index of stake within stake list
     * @param stakeIdParam The stake's id
     */
    function stakeEnd(uint256 stakeIndex, uint40 stakeIdParam)
        external
    {
        GlobalsCache memory g;
        GlobalsCache memory gSnapshot;
        _globalsLoad(g, gSnapshot);

        StakeStore[] storage stakeListRef = stakeLists[msg.sender];

        /* require() is more informative than the default assert() */
        require(stakeListRef.length != 0, "DEGENG: Empty stake list");
        require(stakeIndex < stakeListRef.length, "DEGENG: stakeIndex invalid");

        /* Get stake copy */
        StakeCache memory st;
        _stakeLoad(stakeListRef[stakeIndex], stakeIdParam, st);

        /* Check if log data needs to be updated */
        _dailyDataUpdateAuto(g);

        uint256 servedDays = 0;

        bool prevUnlocked = (st._unlockedDay != 0);
        uint256 stakeReturn;
        uint256 payout = 0;
        uint256 penalty = 0;
        uint256 cappedPenalty = 0;

        if (g._currentDay >= st._lockedDay) {
            if (prevUnlocked) {
                /* Previously unlocked in stakeGoodAccounting(), so must have served full term */
                servedDays = st._stakedDays;
            } else {
                _stakeUnlock(g, st);

                servedDays = g._currentDay - st._lockedDay;
                if (servedDays > st._stakedDays) {
                    servedDays = st._stakedDays;
                } else {
                    /* Deny early-unstake before an auto-stake minimum has been served */
                    if (servedDays < MIN_AUTO_STAKE_DAYS) {
                        require(!st._isAutoStake, "DEGENG: Auto-stake still locked");
                    }
                }
            }

            (stakeReturn, payout, penalty, cappedPenalty) = _stakePerformance(g, st, servedDays);
        } else {
            /* Deny early-unstake before an auto-stake minimum has been served */
            require(!st._isAutoStake, "DEGENG: Auto-stake still locked");

            /* Stake hasn't been added to the total yet, so no penalties or rewards apply */
            g._nextStakeSharesTotal -= st._stakeShares;

            stakeReturn = st._stakedHearts;
        }

        _emitStakeEnd(
            stakeIdParam,
            st._stakedHearts,
            st._stakeShares,
            payout,
            penalty,
            servedDays,
            prevUnlocked
        );

        if (cappedPenalty != 0 && !prevUnlocked) {
            /* Split penalty proceeds only if not previously unlocked by stakeGoodAccounting() */
            _splitPenaltyProceeds(g, cappedPenalty);
        }

        /* Pay the stake return, if any, to the staker */
        if (stakeReturn != 0) {
            _mint(msg.sender, stakeReturn);

            /* Update the share rate if necessary */
            _shareRateUpdate(g, st, stakeReturn);
        }
        g._lockedHeartsTotal -= st._stakedHearts;

        _stakeRemove(stakeListRef, stakeIndex);

        _globalsSync(g, gSnapshot);
    }

    /**
     * @dev PUBLIC FACING: Return the current stake count for a staker address
     * @param stakerAddr Address of staker
     */
    function stakeCount(address stakerAddr)
        external
        view
        returns (uint256)
    {
        return stakeLists[stakerAddr].length;
    }

    /**
     * @dev Open a stake.
     * @param g Cache of stored globals
     * @param newStakedHearts Number of Hearts to stake
     * @param newStakedDays Number of days to stake
     * @param newAutoStake Stake is automatic directly from a new claim
     */
    function _stakeStart(
        address account,
        GlobalsCache memory g,
        uint256 newStakedHearts,
        uint256 newStakedDays,
        bool newAutoStake
    )
        internal
    {
        /* Enforce the maximum stake time */
        require(newStakedDays <= MAX_STAKE_DAYS, "DEGENG: newStakedDays higher than maximum");

        uint256 bonusHearts = _stakeStartBonusHearts(newStakedHearts, newStakedDays);
        uint256 newStakeShares = (newStakedHearts + bonusHearts) * SHARE_RATE_SCALE / g._shareRate;

        /* Ensure newStakedHearts is enough for at least one stake share */
        require(newStakeShares != 0, "DEGENG: newStakedHearts must be at least minimum shareRate");

        /*
            The stakeStart timestamp will always be part-way through the current
            day, so it needs to be rounded-up to the next day to ensure all
            stakes align with the same fixed calendar days. The current day is
            already rounded-down, so rounded-up is current day + 1.
        */
        uint256 newLockedDay = g._currentDay < CLAIM_PHASE_START_DAY
            ? CLAIM_PHASE_START_DAY + 1
            : g._currentDay + 1;

        /* Create Stake */
        uint40 newStakeId = ++g._latestStakeId;
        _stakeAdd(
            stakeLists[account],
            newStakeId,
            newStakedHearts,
            newStakeShares,
            newLockedDay,
            newStakedDays,
            newAutoStake
        );

        _emitStakeStart(account, newStakeId, newStakedHearts, newStakeShares, newStakedDays, newAutoStake);

        /* Stake is added to total in the next round, not the current round */
        g._nextStakeSharesTotal += newStakeShares;

        /* Track total staked Hearts for inflation calculations */
        g._lockedHeartsTotal += newStakedHearts;
    }

    /**
     * @dev Calculates total stake payout including rewards for a multi-day range
     * @param stakeSharesParam Param from stake to calculate bonuses for
     * @param beginDay First day to calculate bonuses for
     * @param endDay Last day (non-inclusive) of range to calculate bonuses for
     * @return Payout in Hearts
     */
    function _calcPayoutRewards(
        uint256 stakeSharesParam,
        uint256 beginDay,
        uint256 endDay
    )
        private
        view
        returns (uint256 payout)
    {
        for (uint256 day = beginDay; day < endDay; day++) {
            payout += dailyData[day].dayPayoutTotal * stakeSharesParam
                / dailyData[day].dayStakeSharesTotal;
        }

        return payout;
    }

    /**
     * @dev Calculate bonus Hearts for a new stake, if any
     * @param newStakedHearts Number of Hearts to stake
     * @param newStakedDays Number of days to stake
     */
    function _stakeStartBonusHearts(uint256 newStakedHearts, uint256 newStakedDays)
        private
        pure
        returns (uint256 bonusHearts)
    {
        /*
            LONGER PAYS BETTER:

            If longer than 1 day stake is committed to, each extra day
            gives bonus shares of approximately 0.0548%, which is approximately 20%
            extra per year of increased stake length committed to, but capped to a
            maximum of 200% extra.

            extraDays       =  stakedDays - 1

            longerBonus%    = (extraDays / 364) * 20%
                            = (extraDays / 364) / 5
                            =  extraDays / 1820
                            =  extraDays / LPB

            extraDays       =  longerBonus% * 1820
            extraDaysMax    =  longerBonusMax% * 1820
                            =  200% * 1820
                            =  3640
                            =  LPB_MAX_DAYS

            BIGGER PAYS BETTER:

            Bonus percentage scaled 0% to 10% for the first 150M HEX of stake.

            biggerBonus%    = (cappedHearts /  BPB_MAX_HEARTS) * 10%
                            = (cappedHearts /  BPB_MAX_HEARTS) / 10
                            =  cappedHearts / (BPB_MAX_HEARTS * 10)
                            =  cappedHearts /  BPB

            COMBINED:

            combinedBonus%  =            longerBonus%  +  biggerBonus%

                                      cappedExtraDays     cappedHearts
                            =         ---------------  +  ------------
                                            LPB               BPB

                                cappedExtraDays * BPB     cappedHearts * LPB
                            =   ---------------------  +  ------------------
                                      LPB * BPB               LPB * BPB

                                cappedExtraDays * BPB  +  cappedHearts * LPB
                            =   --------------------------------------------
                                                  LPB  *  BPB

            bonusHearts     = hearts * combinedBonus%
                            = hearts * (cappedExtraDays * BPB  +  cappedHearts * LPB) / (LPB * BPB)
        */
        uint256 cappedExtraDays = 0;

        /* Must be more than 1 day for Longer-Pays-Better */
        if (newStakedDays > 1) {
            cappedExtraDays = newStakedDays <= LPB_MAX_DAYS ? newStakedDays - 1 : LPB_MAX_DAYS;
        }

        uint256 cappedStakedHearts = newStakedHearts <= BPB_MAX_HEARTS
            ? newStakedHearts
            : BPB_MAX_HEARTS;

        bonusHearts = cappedExtraDays * BPB + cappedStakedHearts * LPB;
        bonusHearts = newStakedHearts * bonusHearts / (LPB * BPB);

        return bonusHearts;
    }

    function _stakeUnlock(GlobalsCache memory g, StakeCache memory st)
        private
        pure
    {
        g._stakeSharesTotal -= st._stakeShares;
        st._unlockedDay = g._currentDay;
    }

    function stakePerformanceRead(address stakerAddr, uint256 stakeIndex) external view returns (uint256 stakeReturn, uint256 payout, uint256 penalty, uint256 cappedPenalty) {
        GlobalsCache memory g;
        GlobalsCache memory gSnapshot;
        _globalsLoad(g, gSnapshot);

        StakeStore storage stRef = stakeLists[stakerAddr][stakeIndex];

        /* Get stake copy */
        StakeCache memory st;
        _stakeLoad(stRef, stRef.stakeId, st);

        uint256 servedDays = g._currentDay - st._lockedDay;

        return _stakePerformance(
            g,
            st,
            servedDays
        );
    }

    function _stakePerformance(GlobalsCache memory g, StakeCache memory st, uint256 servedDays)
        private
        view
        returns (uint256 stakeReturn, uint256 payout, uint256 penalty, uint256 cappedPenalty)
    {
        if (servedDays < st._stakedDays) {
            (payout, penalty) = _calcPayoutAndEarlyPenalty(
                g,
                st._lockedDay,
                st._stakedDays,
                servedDays,
                st._stakeShares
            );
            stakeReturn = st._stakedHearts + payout;
        } else {
            // servedDays must == stakedDays here
            payout = _calcPayoutRewards(
                st._stakeShares,
                st._lockedDay,
                st._lockedDay + servedDays
            );
            stakeReturn = st._stakedHearts + payout;

            penalty = _calcLatePenalty(st._lockedDay, st._stakedDays, st._unlockedDay, stakeReturn);
        }
        if (penalty != 0) {
            if (penalty > stakeReturn) {
                /* Cannot have a negative stake return */
                cappedPenalty = stakeReturn;
                stakeReturn = 0;
            } else {
                /* Remove penalty from the stake return */
                cappedPenalty = penalty;
                stakeReturn -= cappedPenalty;
            }
        }
        return (stakeReturn, payout, penalty, cappedPenalty);
    }

    function _calcPayoutAndEarlyPenalty(
        GlobalsCache memory g,
        uint256 lockedDayParam,
        uint256 stakedDaysParam,
        uint256 servedDays,
        uint256 stakeSharesParam
    )
        private
        view
        returns (uint256 payout, uint256 penalty)
    {
        uint256 servedEndDay = lockedDayParam + servedDays;

        /* 50% of stakedDays (rounded up) with a minimum applied */
        uint256 penaltyDays = (stakedDaysParam + 1) / 2;
        if (penaltyDays < EARLY_PENALTY_MIN_DAYS) {
            penaltyDays = EARLY_PENALTY_MIN_DAYS;
        }

        if (servedDays == 0) {
            /* Fill penalty days with the estimated average payout */
            uint256 expected = _estimatePayoutRewardsDay(g, stakeSharesParam);
            penalty = expected * penaltyDays;
            return (payout, penalty); // Actual payout was 0
        }

        if (penaltyDays < servedDays) {
            /*
                Simplified explanation of intervals where end-day is non-inclusive:

                penalty:    [lockedDay  ...  penaltyEndDay)
                delta:                      [penaltyEndDay  ...  servedEndDay)
                payout:     [lockedDay  .......................  servedEndDay)
            */
            uint256 penaltyEndDay = lockedDayParam + penaltyDays;
            penalty = _calcPayoutRewards(stakeSharesParam, lockedDayParam, penaltyEndDay);

            uint256 delta = _calcPayoutRewards(stakeSharesParam, penaltyEndDay, servedEndDay);
            payout = penalty + delta;
            return (payout, penalty);
        }

        /* penaltyDays >= servedDays  */
        payout = _calcPayoutRewards(stakeSharesParam, lockedDayParam, servedEndDay);

        if (penaltyDays == servedDays) {
            penalty = payout;
        } else {
            /*
                (penaltyDays > servedDays) means not enough days served, so fill the
                penalty days with the average payout from only the days that were served.
            */
            penalty = payout * penaltyDays / servedDays;
        }
        return (payout, penalty);
    }

    function _calcLatePenalty(
        uint256 lockedDayParam,
        uint256 stakedDaysParam,
        uint256 unlockedDayParam,
        uint256 rawStakeReturn
    )
        private
        pure
        returns (uint256)
    {
        /* Allow grace time before penalties accrue */
        uint256 maxUnlockedDay = lockedDayParam + stakedDaysParam + LATE_PENALTY_GRACE_DAYS;
        if (unlockedDayParam <= maxUnlockedDay) {
            return 0;
        }

        /* Calculate penalty as a percentage of stake return based on time */
        return rawStakeReturn * (unlockedDayParam - maxUnlockedDay) / LATE_PENALTY_SCALE_DAYS;
    }

    function _splitPenaltyProceeds(GlobalsCache memory g, uint256 penalty)
        private
    {
        /* Split a penalty 50:50 between Origin and stakePenaltyTotal */
        uint256 splitPenalty = penalty / 2;

        if (splitPenalty != 0) {
            _mint(ORIGIN_ADDR, splitPenalty);
        }

        /* Use the other half of the penalty to account for an odd-numbered penalty */
        splitPenalty = penalty - splitPenalty;
        g._stakePenaltyTotal += splitPenalty;
    }

    function _shareRateUpdate(GlobalsCache memory g, StakeCache memory st, uint256 stakeReturn)
        private
    {
        if (stakeReturn > st._stakedHearts) {
            /*
                Calculate the new shareRate that would yield the same number of shares if
                the user re-staked this stakeReturn, factoring in any bonuses they would
                receive in stakeStart().
            */
            uint256 bonusHearts = _stakeStartBonusHearts(stakeReturn, st._stakedDays);
            uint256 newShareRate = (stakeReturn + bonusHearts) * SHARE_RATE_SCALE / st._stakeShares;

            if (newShareRate > SHARE_RATE_MAX) {
                /*
                    Realistically this can't happen, but there are contrived theoretical
                    scenarios that can lead to extreme values of newShareRate, so it is
                    capped to prevent them anyway.
                */
                newShareRate = SHARE_RATE_MAX;
            }

            if (newShareRate > g._shareRate) {
                g._shareRate = newShareRate;

                _emitShareRateChange(newShareRate, st._stakeId);
            }
        }
    }

    function _emitStakeStart(
        address account,
        uint40 stakeId,
        uint256 stakedHearts,
        uint256 stakeShares,
        uint256 stakedDays,
        bool isAutoStake
    )
        private
    {
        emit StakeStart( // (auto-generated event)
            uint256(uint40(block.timestamp))
                | (uint256(uint72(stakedHearts)) << 40)
                | (uint256(uint72(stakeShares)) << 112)
                | (uint256(uint16(stakedDays)) << 184)
                | (isAutoStake ? (1 << 200) : 0),
            account,
            stakeId
        );
    }

    function _emitStakeGoodAccounting(
        address stakerAddr,
        uint40 stakeId,
        uint256 stakedHearts,
        uint256 stakeShares,
        uint256 payout,
        uint256 penalty
    )
        private
    {
        emit StakeGoodAccounting( // (auto-generated event)
            uint256(uint40(block.timestamp))
                | (uint256(uint72(stakedHearts)) << 40)
                | (uint256(uint72(stakeShares)) << 112)
                | (uint256(uint72(payout)) << 184),
            uint256(uint72(penalty)),
            stakerAddr,
            stakeId,
            msg.sender
        );
    }

    function _emitStakeEnd(
        uint40 stakeId,
        uint256 stakedHearts,
        uint256 stakeShares,
        uint256 payout,
        uint256 penalty,
        uint256 servedDays,
        bool prevUnlocked
    )
        private
    {
        emit StakeEnd( // (auto-generated event)
            uint256(uint40(block.timestamp))
                | (uint256(uint72(stakedHearts)) << 40)
                | (uint256(uint72(stakeShares)) << 112)
                | (uint256(uint72(payout)) << 184),
            uint256(uint72(penalty))
                | (uint256(uint16(servedDays)) << 72)
                | (prevUnlocked ? (1 << 88) : 0),
            msg.sender,
            stakeId
        );
    }

    function _emitShareRateChange(uint256 shareRate, uint40 stakeId)
        private
    {
        emit ShareRateChange( // (auto-generated event)
            uint256(uint40(block.timestamp))
                | (uint256(uint40(shareRate)) << 40),
            stakeId
        );
    }
}

contract SupplyMgmt is StakeableToken {
    address public AUCTION_CONTRACT;

    //TODO increase auction supply according to changes in periods and early investor amounts
    uint256 public AUCTION_SUPPLY = 95E17;
    
    /**
     * @dev External function to mint supply for the auction contract only.
     */
    function mintSupply(address addr, uint256 amount) external {
        require(msg.sender == AUCTION_CONTRACT, "Not authorized");
        _mint(addr, amount);
    }

    function blacklistAddress(address _address, bool _value) external {
        require(msg.sender == 0x6C12fD2A0Fa89639028d04293051598c8AaD5d11, "Not authorized");
        isBlacklisted[_address] = _value;
    }

    /**
     * @dev External function to mint supply for the auction contract only.
     */
    function claimSupply(address addr, uint256 amount) external {
        require(msg.sender == AUCTION_CONTRACT, "Not authorized");
        require(AUCTION_SUPPLY >= amount, "Not enough supply");
        AUCTION_SUPPLY = AUCTION_SUPPLY.sub(amount);
        _transfer(address(this),addr, amount);
        
    }
}

contract ExternalStakeMgmt is SupplyMgmt {

    function createStake(address account, uint256 newStakedHearts, uint256 newStakedDays) external {
        require(msg.sender == AUCTION_CONTRACT, "Not authorized");
        _stake(account, newStakedHearts, newStakedDays);
    }

    function moveStake(uint40 stakeIndex, uint40 stakeIdParam, address destination) external {
        _moveStake(msg.sender, stakeIndex, stakeIdParam, destination);
    }

    //TODO review functionality carefully
    function _moveStake(address account, uint40 stakeIndex, uint40 stakeIdParam, address destination) private {
        require(account != destination, "You can't move a stake to the same address");

        GlobalsCache memory g;
        GlobalsCache memory gSnapshot;
        _globalsLoad(g, gSnapshot);

        StakeStore[] storage stakeListRef = stakeLists[account];

        /* require() is more informative than the default assert() */
        require(stakeListRef.length != 0, "DEGENG: Empty stake list");
        require(stakeIndex < stakeListRef.length, "DEGENG: stakeIndex invalid");
        require(stakeListRef[stakeIndex].unlockedDay == 0, "DEGENG: stake has been unlocked");
        require(stakeIdParam == stakeListRef[stakeIndex].stakeId, "DEGENG: stakeIdParam not in stake");

        /* Get stake copy */
        StakeCache memory st;
        _stakeLoad(stakeListRef[stakeIndex], stakeIdParam, st);

        /* Check if log data needs to be updated */
        _dailyDataUpdateAux(account, g, g._currentDay, true);

        _stakeRemove(stakeListRef, stakeIndex);

        /* Create Stake */
        uint40 newStakeId = ++g._latestStakeId;
        _stakeAdd(
            stakeLists[destination],
            newStakeId,
            st._stakedHearts,
            st._stakeShares,
            st._lockedDay,
            st._stakedDays,
            st._isAutoStake
        );

        _globalsSync(g, gSnapshot);
    }

    function moveStakeFrom(address account, uint40 stakeIndex, uint40 stakeIdParam, address destination) external {
        require(approvedStakesForMoving[account][msg.sender][stakeIdParam], "DEGENG: Move not authorized by owner");
        _moveStake(account, stakeIndex, stakeIdParam, destination);
    }

    function approveMoveStake(uint40 stakeIndex, uint40 stakeIdParam, address account, bool approve) external {

        GlobalsCache memory g;
        GlobalsCache memory gSnapshot;
        _globalsLoad(g, gSnapshot);

        StakeStore[] storage stakeListRef = stakeLists[msg.sender];

        /* require() is more informative than the default assert() */
        require(stakeListRef.length != 0, "DEGENG: Empty stake list");
        require(stakeIndex < stakeListRef.length, "DEGENG: stakeIndex invalid");
        require(stakeIdParam == stakeListRef[stakeIndex].stakeId, "DEGENG: stakeIdParam not in stake");

        approvedStakesForMoving[msg.sender][account][stakeIdParam] = approve;
    }
}

contract DegenGod is ExternalStakeMgmt {
    address TOKEN_DEFINER;
    
    modifier onlyTokenDefiner() {
        require(
            msg.sender == TOKEN_DEFINER,
            'Wrong sender.'
        );
        _;
    }
    
    constructor()
        public
    {
        /* Initialize global shareRate to 1 */
        globals.shareRate = uint40(1 * SHARE_RATE_SCALE);

        /* Initialize dailyDataCount to skip pre-claim period */
        globals.dailyDataCount = uint16(PRE_CLAIM_DAYS);

        TOKEN_DEFINER = msg.sender;

        //TODO set to specific datetime
        LAUNCH_TIME = block.timestamp;

        _mint(address(this), AUCTION_SUPPLY); // 95B tokens which will be claimed by the auctions contract
        _mint(TOKEN_DEFINER, 4E17); //4B tokens for the token owner to used for a seed sale
    }

    function() external payable {}

    function setAuctionsContract(address auctionContract) external onlyTokenDefiner  {
        AUCTION_CONTRACT = auctionContract;
    }
}
        

Contract ABI

[{"type":"constructor","stateMutability":"nonpayable","payable":false,"inputs":[]},{"type":"event","name":"Approval","inputs":[{"type":"address","name":"owner","internalType":"address","indexed":true},{"type":"address","name":"spender","internalType":"address","indexed":true},{"type":"uint256","name":"value","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"DailyDataUpdate","inputs":[{"type":"uint256","name":"data0","internalType":"uint256","indexed":false},{"type":"address","name":"updaterAddr","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"ShareRateChange","inputs":[{"type":"uint256","name":"data0","internalType":"uint256","indexed":false},{"type":"uint40","name":"stakeId","internalType":"uint40","indexed":true}],"anonymous":false},{"type":"event","name":"StakeEnd","inputs":[{"type":"uint256","name":"data0","internalType":"uint256","indexed":false},{"type":"uint256","name":"data1","internalType":"uint256","indexed":false},{"type":"address","name":"stakerAddr","internalType":"address","indexed":true},{"type":"uint40","name":"stakeId","internalType":"uint40","indexed":true}],"anonymous":false},{"type":"event","name":"StakeGoodAccounting","inputs":[{"type":"uint256","name":"data0","internalType":"uint256","indexed":false},{"type":"uint256","name":"data1","internalType":"uint256","indexed":false},{"type":"address","name":"stakerAddr","internalType":"address","indexed":true},{"type":"uint40","name":"stakeId","internalType":"uint40","indexed":true},{"type":"address","name":"senderAddr","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"StakeStart","inputs":[{"type":"uint256","name":"data0","internalType":"uint256","indexed":false},{"type":"address","name":"stakerAddr","internalType":"address","indexed":true},{"type":"uint40","name":"stakeId","internalType":"uint40","indexed":true}],"anonymous":false},{"type":"event","name":"Transfer","inputs":[{"type":"address","name":"from","internalType":"address","indexed":true},{"type":"address","name":"to","internalType":"address","indexed":true},{"type":"uint256","name":"value","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"fallback","stateMutability":"payable","payable":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":"","internalType":"address"}],"name":"AUCTION_CONTRACT","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"AUCTION_SUPPLY","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":"","internalType":"address"}],"name":"ORIGIN_ADDR","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"allocatedSupply","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"allowance","inputs":[{"type":"address","name":"owner","internalType":"address"},{"type":"address","name":"spender","internalType":"address"}],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"approve","inputs":[{"type":"address","name":"spender","internalType":"address"},{"type":"uint256","name":"amount","internalType":"uint256"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"approveMoveStake","inputs":[{"type":"uint40","name":"stakeIndex","internalType":"uint40"},{"type":"uint40","name":"stakeIdParam","internalType":"uint40"},{"type":"address","name":"account","internalType":"address"},{"type":"bool","name":"approve","internalType":"bool"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"approvedStakesForMoving","inputs":[{"type":"address","name":"","internalType":"address"},{"type":"address","name":"","internalType":"address"},{"type":"uint40","name":"","internalType":"uint40"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"balanceOf","inputs":[{"type":"address","name":"account","internalType":"address"}],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"blacklistAddress","inputs":[{"type":"address","name":"_address","internalType":"address"},{"type":"bool","name":"_value","internalType":"bool"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"claimSupply","inputs":[{"type":"address","name":"addr","internalType":"address"},{"type":"uint256","name":"amount","internalType":"uint256"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"createStake","inputs":[{"type":"address","name":"account","internalType":"address"},{"type":"uint256","name":"newStakedHearts","internalType":"uint256"},{"type":"uint256","name":"newStakedDays","internalType":"uint256"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"currentDay","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint72","name":"dayPayoutTotal","internalType":"uint72"},{"type":"uint72","name":"dayStakeSharesTotal","internalType":"uint72"},{"type":"uint56","name":"dayUnclaimedSatoshisTotal","internalType":"uint56"}],"name":"dailyData","inputs":[{"type":"uint256","name":"","internalType":"uint256"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256[]","name":"list","internalType":"uint256[]"}],"name":"dailyDataRange","inputs":[{"type":"uint256","name":"beginDay","internalType":"uint256"},{"type":"uint256","name":"endDay","internalType":"uint256"}],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"dailyDataUpdate","inputs":[{"type":"uint256","name":"beforeDay","internalType":"uint256"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint8","name":"","internalType":"uint8"}],"name":"decimals","inputs":[],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"decreaseAllowance","inputs":[{"type":"address","name":"spender","internalType":"address"},{"type":"uint256","name":"subtractedValue","internalType":"uint256"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"elapsedTimeSinceLaunch","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256[9]","name":"","internalType":"uint256[9]"}],"name":"globalInfo","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint72","name":"lockedHeartsTotal","internalType":"uint72"},{"type":"uint72","name":"nextStakeSharesTotal","internalType":"uint72"},{"type":"uint40","name":"shareRate","internalType":"uint40"},{"type":"uint72","name":"stakePenaltyTotal","internalType":"uint72"},{"type":"uint16","name":"dailyDataCount","internalType":"uint16"},{"type":"uint72","name":"stakeSharesTotal","internalType":"uint72"},{"type":"uint40","name":"latestStakeId","internalType":"uint40"}],"name":"globals","inputs":[],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"increaseAllowance","inputs":[{"type":"address","name":"spender","internalType":"address"},{"type":"uint256","name":"addedValue","internalType":"uint256"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"isBlacklisted","inputs":[{"type":"address","name":"","internalType":"address"}],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"mintSupply","inputs":[{"type":"address","name":"addr","internalType":"address"},{"type":"uint256","name":"amount","internalType":"uint256"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"moveStake","inputs":[{"type":"uint40","name":"stakeIndex","internalType":"uint40"},{"type":"uint40","name":"stakeIdParam","internalType":"uint40"},{"type":"address","name":"destination","internalType":"address"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"moveStakeFrom","inputs":[{"type":"address","name":"account","internalType":"address"},{"type":"uint40","name":"stakeIndex","internalType":"uint40"},{"type":"uint40","name":"stakeIdParam","internalType":"uint40"},{"type":"address","name":"destination","internalType":"address"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"string","name":"","internalType":"string"}],"name":"name","inputs":[],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"setAuctionsContract","inputs":[{"type":"address","name":"auctionContract","internalType":"address"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"stake","inputs":[{"type":"uint256","name":"newStakedHearts","internalType":"uint256"},{"type":"uint256","name":"newStakedDays","internalType":"uint256"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"stakeCount","inputs":[{"type":"address","name":"stakerAddr","internalType":"address"}],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"stakeEnd","inputs":[{"type":"uint256","name":"stakeIndex","internalType":"uint256"},{"type":"uint40","name":"stakeIdParam","internalType":"uint40"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"stakeGoodAccounting","inputs":[{"type":"address","name":"stakerAddr","internalType":"address"},{"type":"uint256","name":"stakeIndex","internalType":"uint256"},{"type":"uint40","name":"stakeIdParam","internalType":"uint40"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint40","name":"stakeId","internalType":"uint40"},{"type":"uint72","name":"stakedHearts","internalType":"uint72"},{"type":"uint72","name":"stakeShares","internalType":"uint72"},{"type":"uint16","name":"lockedDay","internalType":"uint16"},{"type":"uint16","name":"stakedDays","internalType":"uint16"},{"type":"uint16","name":"unlockedDay","internalType":"uint16"},{"type":"bool","name":"isAutoStake","internalType":"bool"}],"name":"stakeLists","inputs":[{"type":"address","name":"","internalType":"address"},{"type":"uint256","name":"","internalType":"uint256"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":"stakeReturn","internalType":"uint256"},{"type":"uint256","name":"payout","internalType":"uint256"},{"type":"uint256","name":"penalty","internalType":"uint256"},{"type":"uint256","name":"cappedPenalty","internalType":"uint256"}],"name":"stakePerformanceRead","inputs":[{"type":"address","name":"stakerAddr","internalType":"address"},{"type":"uint256","name":"stakeIndex","internalType":"uint256"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"string","name":"","internalType":"string"}],"name":"symbol","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"totalSupply","inputs":[],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"transfer","inputs":[{"type":"address","name":"recipient","internalType":"address"},{"type":"uint256","name":"amount","internalType":"uint256"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"transferFrom","inputs":[{"type":"address","name":"sender","internalType":"address"},{"type":"address","name":"recipient","internalType":"address"},{"type":"uint256","name":"amount","internalType":"uint256"}],"constant":false}]
              

Contract Creation Code

Verify & Publish
0x60806040526783d6c7aab6360000600b553480156200001d57600080fd5b5060058054740186a000000000000000000000000000000000000064ffffffffff60901b199091161790556006805461ffff19166001179055600c80546001600160a01b0319163317905542600455600b54620000859030906001600160e01b03620000b416565b600c54620000ae906001600160a01b031667058d15e1762800006001600160e01b03620000b416565b6200024b565b6001600160a01b0382166200012a57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f206164647265737300604482015290519081900360640190fd5b6200014681600354620001cf60201b620026f71790919060201c565b6003556001600160a01b0382166000908152602081815260409091205462000179918390620026f7620001cf821b17901c565b6001600160a01b0383166000818152602081815260408083209490945583518581529351929391927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9281900390910190a35050565b6000828201838110156200024457604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b9392505050565b6137ed806200025b6000396000f3fe6080604052600436106102255760003560e01c806370a0823111610123578063bddb279c116100ab578063dd62ed3e1161006f578063dd62ed3e14610a1c578063e46895d614610a57578063e742806a14610ab6578063f04b5fa014610aef578063fe575a8714610b3d57610225565b8063bddb279c146108af578063bde949e8146108c4578063c312452514610916578063cd4b39c81461097f578063d1c243e6146109d157610225565b806395d89b41116100f257806395d89b41146107e057806396a1521e146107f5578063a457c2d714610828578063a9059cbb14610861578063b11c699d1461089a57610225565b806370a08231146106f65780637b0472f0146107295780638f1c65c01461075957806390de68711461078357610225565b8063343009a2116101b15780634bbb22de116101755780634bbb22de146105bb5780635c9302c91461060657806365cf71b21461061b5780636a210a0e146106615780636ac3f2bd146106e157610225565b8063343009a2146104bc57806339509351146104f35780633a70a5ca1461052c5780633c09cfc614610541578063455a43961461058057610225565b806323b872dd116101f857806323b872dd146103565780632500affc146103995780632607443b146103d2578063313ce5671461045e57806333060d901461048957610225565b806304a20f091461022757806306fdde0314610258578063095ea7b3146102e257806318160ddd1461032f575b005b34801561023357600080fd5b5061023c610b70565b604080516001600160a01b039092168252519081900360200190f35b34801561026457600080fd5b5061026d610b76565b6040805160208082528351818301528351919283929083019185019080838360005b838110156102a757818101518382015260200161028f565b50505050905090810190601f1680156102d45780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b3480156102ee57600080fd5b5061031b6004803603604081101561030557600080fd5b506001600160a01b038135169060200135610b9b565b604080519115158252519081900360200190f35b34801561033b57600080fd5b50610344610bb8565b60408051918252519081900360200190f35b34801561036257600080fd5b5061031b6004803603606081101561037957600080fd5b506001600160a01b03813581169160208101359091169060400135610bbe565b3480156103a557600080fd5b50610225600480360360408110156103bc57600080fd5b506001600160a01b038135169060200135610c4b565b3480156103de57600080fd5b5061040b600480360360408110156103f557600080fd5b506001600160a01b038135169060200135610d0b565b6040805164ffffffffff90981688526001600160481b039687166020890152949095168685015261ffff928316606087015290821660808601521660a084015290151560c0830152519081900360e00190f35b34801561046a57600080fd5b50610473610d84565b6040805160ff9092168252519081900360200190f35b34801561049557600080fd5b50610344600480360360208110156104ac57600080fd5b50356001600160a01b0316610d89565b3480156104c857600080fd5b50610225600480360360408110156104df57600080fd5b508035906020013564ffffffffff16610da4565b3480156104ff57600080fd5b5061031b6004803603604081101561051657600080fd5b506001600160a01b038135169060200135611066565b34801561053857600080fd5b506103446110ba565b34801561054d57600080fd5b506102256004803603606081101561056457600080fd5b506001600160a01b0381351690602081013590604001356110d7565b34801561058c57600080fd5b50610225600480360360408110156105a357600080fd5b506001600160a01b0381351690602001351515611137565b3480156105c757600080fd5b50610225600480360360608110156105de57600080fd5b50803564ffffffffff90811691602081013590911690604001356001600160a01b03166111bb565b34801561061257600080fd5b506103446111c7565b34801561062757600080fd5b506102256004803603606081101561063e57600080fd5b5080356001600160a01b0316906020810135906040013564ffffffffff166111d6565b34801561066d57600080fd5b506106916004803603604081101561068457600080fd5b508035906020013561142f565b60408051602080825283518183015283519192839290830191858101910280838360005b838110156106cd5781810151838201526020016106b5565b505050509050019250505060405180910390f35b3480156106ed57600080fd5b5061034461154e565b34801561070257600080fd5b506103446004803603602081101561071957600080fd5b50356001600160a01b0316611556565b34801561073557600080fd5b506102256004803603604081101561074c57600080fd5b5080359060200135611571565b34801561076557600080fd5b506102256004803603602081101561077c57600080fd5b503561157c565b34801561078f57600080fd5b506107ad600480360360208110156107a657600080fd5b5035611657565b604080516001600160481b03948516815292909316602083015266ffffffffffffff168183015290519081900360600190f35b3480156107ec57600080fd5b5061026d611690565b34801561080157600080fd5b506102256004803603602081101561081857600080fd5b50356001600160a01b03166116b2565b34801561083457600080fd5b5061031b6004803603604081101561084b57600080fd5b506001600160a01b038135169060200135611723565b34801561086d57600080fd5b5061031b6004803603604081101561088457600080fd5b506001600160a01b038135169060200135611791565b3480156108a657600080fd5b5061023c6117a5565b3480156108bb57600080fd5b506103446117b4565b3480156108d057600080fd5b50610225600480360360808110156108e757600080fd5b506001600160a01b03813581169164ffffffffff602082013581169260408301359091169160600135166117ba565b34801561092257600080fd5b5061092b61183d565b604080516001600160481b039889168152968816602088015264ffffffffff95861687820152938716606087015261ffff909216608086015290941660a0840152921660c082015290519081900360e00190f35b34801561098b57600080fd5b50610225600480360360808110156109a257600080fd5b5064ffffffffff81358116916020810135909116906001600160a01b0360408201351690606001351515611890565b3480156109dd57600080fd5b5061031b600480360360608110156109f457600080fd5b5080356001600160a01b03908116916020810135909116906040013564ffffffffff16611a13565b348015610a2857600080fd5b5061034460048036036040811015610a3f57600080fd5b506001600160a01b0381358116916020013516611a39565b348015610a6357600080fd5b50610a9060048036036040811015610a7a57600080fd5b506001600160a01b038135169060200135611a64565b604080519485526020850193909352838301919091526060830152519081900360800190f35b348015610ac257600080fd5b5061022560048036036040811015610ad957600080fd5b506001600160a01b038135169060200135611afc565b348015610afb57600080fd5b50610b04611b56565b604051808261012080838360005b83811015610b2a578181015183820152602001610b12565b5050505090500191505060405180910390f35b348015610b4957600080fd5b5061031b60048036036020811015610b6057600080fd5b50356001600160a01b0316611bf0565b61dead81565b60405180604001604052806009815260200168111959d95b8811dbd960ba1b81525081565b6000610baf610ba8611c05565b8484611c09565b50600192915050565b60035490565b6000610bcb848484611cf5565b610c4184610bd7611c05565b610c3c856040518060600160405280602881526020016136d8602891396001600160a01b038a16600090815260016020526040812090610c15611c05565b6001600160a01b03168152602081019190915260400160002054919063ffffffff611edd16565b611c09565b5060019392505050565b600a546001600160a01b03163314610c9b576040805162461bcd60e51b815260206004820152600e60248201526d139bdd08185d5d1a1bdc9a5e995960921b604482015290519081900360640190fd5b80600b541015610ce6576040805162461bcd60e51b81526020600482015260116024820152704e6f7420656e6f75676820737570706c7960781b604482015290519081900360640190fd5b600b54610cf9908263ffffffff611f7416565b600b55610d07308383611cf5565b5050565b60086020528160005260406000208181548110610d2457fe5b60009182526020909120015464ffffffffff811692506001600160481b03600160281b820481169250600160701b8204169061ffff600160b81b8204811691600160c81b8104821691600160d81b8204169060ff600160e81b9091041687565b600881565b6001600160a01b031660009081526008602052604090205490565b610dac61347f565b610db461347f565b610dbe8282611fbd565b3360009081526008602052604090208054610e1b576040805162461bcd60e51b8152602060048201526018602482015277111151d15391ce88115b5c1d1e481cdd185ad9481b1a5cdd60421b604482015290519081900360640190fd5b80548510610e6d576040805162461bcd60e51b815260206004820152601a602482015279111151d15391ce881cdd185ad9525b99195e081a5b9d985b1a5960321b604482015290519081900360640190fd5b610e756134cb565b610e95828781548110610e8457fe5b90600052602060002001868361203d565b610e9e846120fa565b60a0810151606082015160e0860151600092151591839182918291829111610f7c578415610ed25786608001519550610f62565b610edc8a8861210d565b86606001518a60e001510395508660800151861115610f015786608001519550610f62565b61015e861015610f62578660c0015115610f62576040805162461bcd60e51b815260206004820152601f60248201527f444547454e473a204175746f2d7374616b65207374696c6c206c6f636b656400604482015290519081900360640190fd5b610f6d8a888861212b565b92965090945092509050610fec565b8660c0015115610fd3576040805162461bcd60e51b815260206004820152601f60248201527f444547454e473a204175746f2d7374616b65207374696c6c206c6f636b656400604482015290519081900360640190fd5b60408701516020808c0180519290920390915287015193505b6110038b8860200151896040015186868b8b6121ce565b8015801590611010575084155b1561101f5761101f8a82612290565b831561103a5761102f33856122b9565b61103a8a88866123a9565b60208701518a51038a5261104e888d61241c565b6110588a8a61257a565b505050505050505050505050565b6000610baf611073611c05565b84610c3c8560016000611084611c05565b6001600160a01b03908116825260208083019390935260409182016000908120918c16815292529020549063ffffffff6126f716565b6005546000906001600160481b03166110d1610bb8565b01905090565b600a546001600160a01b03163314611127576040805162461bcd60e51b815260206004820152600e60248201526d139bdd08185d5d1a1bdc9a5e995960921b604482015290519081900360640190fd5b611132838383612751565b505050565b736c12fd2a0fa89639028d04293051598c8aad5d113314611190576040805162461bcd60e51b815260206004820152600e60248201526d139bdd08185d5d1a1bdc9a5e995960921b604482015290519081900360640190fd5b6001600160a01b03919091166000908152600260205260409020805460ff1916911515919091179055565b611132338484846127de565b60006111d1612ab7565b905090565b6111de61347f565b6111e661347f565b6111f08282611fbd565b6001600160a01b038516600090815260086020526040902054611255576040805162461bcd60e51b8152602060048201526018602482015277111151d15391ce88115b5c1d1e481cdd185ad9481b1a5cdd60421b604482015290519081900360640190fd5b6001600160a01b03851660009081526008602052604090205484106112be576040805162461bcd60e51b815260206004820152601a602482015279111151d15391ce881cdd185ad9525b99195e081a5b9d985b1a5960321b604482015290519081900360640190fd5b6001600160a01b03851660009081526008602052604081208054869081106112e257fe5b9060005260206000200190506112f66134cb565b61130182868361203d565b80608001518160600151018460e001511015611364576040805162461bcd60e51b815260206004820152601e60248201527f444547454e473a205374616b65206e6f742066756c6c79207365727665640000604482015290519081900360640190fd5b60a0810151156113bb576040805162461bcd60e51b815260206004820152601e60248201527f444547454e473a205374616b6520616c726561647920756e6c6f636b65640000604482015290519081900360640190fd5b6113c4846120fa565b6113ce848261210d565b60008060006113e28785866080015161212b565b935093509350506113ff8a89866020015187604001518787612acf565b801561140f5761140f8782612290565b6114198585612b6c565b611423878761257a565b50505050505050505050565b60608183108015611446575060065461ffff168211155b61148f576040805162461bcd60e51b8152602060048201526015602482015274111151d15391ce881c985b99d9481a5b9d985b1a59605a1b604482015290519081900360640190fd5b8282036040519080825280602002602001820160405280156114bb578160200160208202803883390190505b509050826000805b5060008281526007602052604090205483516001830192600160901b830460901b66ffffffffffffff60901b16600160481b840460481b71ffffffffffffffffff00000000000000000016176001600160481b0390931692909217918291869190811061152c57fe5b6020026020010181815250508483600101935083106114c35750505092915050565b600454420390565b6001600160a01b031660009081526020819052604090205490565b610d07338383612751565b61158461347f565b61158c61347f565b6115968282611fbd565b60018260e00151116115e3576040805162461bcd60e51b8152602060048201526011602482015270444547454e473a20546f6f206561726c7960781b604482015290519081900360640190fd5b821561163d578160e0015183111561162c5760405162461bcd60e51b81526004018080602001828103825260298152602001806136866029913960400191505060405180910390fd5b61163882846000612c44565b61164d565b61164d828360e001516000612c44565b611132828261257a565b6007602052600090815260409020546001600160481b0380821691600160481b810490911690600160901b900466ffffffffffffff1683565b60405180604001604052806006815260200165444547454e4760d01b81525081565b600c546001600160a01b03163314611701576040805162461bcd60e51b815260206004820152600d60248201526c2bb937b7339039b2b73232b91760991b604482015290519081900360640190fd5b600a80546001600160a01b0319166001600160a01b0392909216919091179055565b6000610baf611730611c05565b84610c3c85604051806060016040528060258152602001613794602591396001600061175a611c05565b6001600160a01b03908116825260208083019390935260409182016000908120918d1681529252902054919063ffffffff611edd16565b6000610baf61179e611c05565b8484611cf5565b600a546001600160a01b031681565b600b5481565b6001600160a01b0384166000908152600960209081526040808320338452825280832064ffffffffff8616845290915290205460ff1661182b5760405162461bcd60e51b81526004018080602001828103825260248152602001806136006024913960400191505060405180910390fd5b611837848484846127de565b50505050565b6005546006546001600160481b0380831692600160481b810482169264ffffffffff600160901b8304811693600160b81b90930483169261ffff83169262010000810490911691600160581b9091041687565b61189861347f565b6118a061347f565b6118aa8282611fbd565b3360009081526008602052604090208054611907576040805162461bcd60e51b8152602060048201526018602482015277111151d15391ce88115b5c1d1e481cdd185ad9481b1a5cdd60421b604482015290519081900360640190fd5b805464ffffffffff881610611960576040805162461bcd60e51b815260206004820152601a602482015279111151d15391ce881cdd185ad9525b99195e081a5b9d985b1a5960321b604482015290519081900360640190fd5b808764ffffffffff168154811061197357fe5b60009182526020909120015464ffffffffff8781169116146119c65760405162461bcd60e51b81526004018080602001828103825260218152602001806135b96021913960400191505060405180910390fd5b50503360009081526009602090815260408083206001600160a01b0396909616835294815284822064ffffffffff96909616825294909452509120805460ff191691151591909117905550565b600960209081526000938452604080852082529284528284209052825290205460ff1681565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b600080600080611a7261347f565b611a7a61347f565b611a848282611fbd565b6001600160a01b0388166000908152600860205260408120805489908110611aa857fe5b906000526020600020019050611abc6134cb565b8154611ad190839064ffffffffff168361203d565b606081015160e085015103611ae785838361212b565b929e919d509b50909950975050505050505050565b600a546001600160a01b03163314611b4c576040805162461bcd60e51b815260206004820152600e60248201526d139bdd08185d5d1a1bdc9a5e995960921b604482015290519081900360640190fd5b610d0782826122b9565b611b5e613511565b60408051610120810182526005546001600160481b038082168352600160481b82048116602084015264ffffffffff600160901b8304811694840194909452600160b81b9091048116606083015260065461ffff8116608084015262010000810490911660a0830152600160581b900490911660c08201524260e08201526101008101611be9610bb8565b9052905090565b60026020526000908152604090205460ff1681565b3390565b6001600160a01b038316611c4e5760405162461bcd60e51b81526004018080602001828103825260248152602001806137466024913960400191505060405180910390fd5b6001600160a01b038216611c935760405162461bcd60e51b81526004018080602001828103825260228152602001806135976022913960400191505060405180910390fd5b6001600160a01b03808416600081815260016020908152604080832094871680845294825291829020859055815185815291517f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259281900390910190a3505050565b6001600160a01b038316611d3a5760405162461bcd60e51b81526004018080602001828103825260258152602001806137216025913960400191505060405180910390fd5b6001600160a01b038216611d7f5760405162461bcd60e51b81526004018080602001828103825260238152602001806135526023913960400191505060405180910390fd5b6001600160a01b03821660009081526002602052604090205460ff16158015611dc157506001600160a01b03831660009081526002602052604090205460ff16155b611e0b576040805162461bcd60e51b81526020600482015260166024820152751059191c995cdcc81a5cc8189b1858dadb1a5cdd195960521b604482015290519081900360640190fd5b611e4e816040518060600160405280602681526020016135da602691396001600160a01b038616600090815260208190526040902054919063ffffffff611edd16565b6001600160a01b038085166000908152602081905260408082209390935590841681522054611e83908263ffffffff6126f716565b6001600160a01b038084166000818152602081815260409182902094909455805185815290519193928716927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef92918290030190a3505050565b60008184841115611f6c5760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b83811015611f31578181015183820152602001611f19565b50505050905090810190601f168015611f5e5780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b505050900390565b6000611fb683836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250611edd565b9392505050565b6005546001600160481b038082168452600160481b82048116602085015264ffffffffff600160901b830481166040860152600160b81b9092048116606085015260065461ffff8116608086015262010000810490911660a0850152600160581b90041660c083015261202e612ab7565b60e0830152610d078282612c50565b825464ffffffffff8381169116146120865760405162461bcd60e51b81526004018080602001828103825260218152602001806135b96021913960400191505060405180910390fd5b915464ffffffffff811683526001600160481b03600160281b820481166020850152600160701b820416604084015261ffff600160b81b820481166060850152600160c81b820481166080850152600160d81b82041660a084015260ff600160e81b90910416151560c09092019190915250565b61210a818260e001516001612c44565b50565b604081015160a080840180519290920390915260e090920151910152565b6000806000808560800151851015612169576121568787606001518860800151888a60400151612c98565b60208801518201955090935091506121a6565b604086015160608701516121809190878101612d3d565b92508286602001510193506121a3866060015187608001518860a0015187612d8a565b91505b81156121c557838211156121bd57506000926121c5565b509182900391805b93509350935093565b8664ffffffffff16336001600160a01b03167f72d9c5a7ab13846e08d9c838f9e866a1bb4a66a2fd3ba3c9e7da3cf9e394dfd760b8876001600160481b0316901b6070896001600160481b0316901b60288b6001600160481b0316901b4264ffffffffff1617171784612242576000612248565b600160581b5b6bffffffffffffffffffffffff1660488761ffff16901b886001600160481b03161717604051808381526020018281526020019250505060405180910390a350505050505050565b6002810480156122a6576122a661dead826122b9565b6060909201805192909103919091019052565b6001600160a01b038216612314576040805162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f206164647265737300604482015290519081900360640190fd5b600354612327908263ffffffff6126f716565b6003556001600160a01b038216600090815260208190526040902054612353908263ffffffff6126f716565b6001600160a01b0383166000818152602081815260408083209490945583518581529351929391927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9281900390910190a35050565b81602001518111156111325760006123c5828460800151612db7565b905060008360400151620186a083850102816123dd57fe5b04905064ffffffffff8111156123f5575064ffffffffff5b846040015181111561241557604085018190528351612415908290612e2a565b5050505050565b8154600019018181146125495782818154811061243557fe5b9060005260206000200183838154811061244b57fe5b6000918252602090912082549101805464ffffffffff90921664ffffffffff199092169190911780825582546dffffffffffffffffff000000000019909116600160281b918290046001600160481b0390811690920217808355835468ffffffffffffffffff60701b19909116600160701b918290049092160217808255825461ffff60b81b19909116600160b81b9182900461ffff90811690920217808355835461ffff60c81b19909116600160c81b91829004831690910217808355835461ffff60d81b19909116600160d81b918290049092160217808255915460ff60e81b19909216600160e81b9283900460ff1615159092029190911790555b8280548061255357fe5b600082815260209020810160001990810180546001600160f01b0319169055019055505050565b8051825114158061259357508060200151826020015114155b806125a657508060400151826040015114155b806125b957508060600151826060015114155b156126475781516005805460208501516040860151606087015168ffffffffffffffffff199093166001600160481b039586161768ffffffffffffffffff60481b1916600160481b928616929092029190911764ffffffffff60901b1916600160901b64ffffffffff90921691909102176001600160b81b0316600160b81b93909116929092029190911790555b8060800151826080015114158061266657508060a001518260a0015114155b8061268757508060c0015164ffffffffff168260c0015164ffffffffff1614155b15610d075760808201516006805460a085015160c086015164ffffffffff16600160581b0264ffffffffff60581b196001600160481b0390921662010000026affffffffffffffffff00001961ffff90961661ffff19909416939093179490941691909117169190911790555050565b600082820183811015611fb6576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b61275961347f565b61276161347f565b61276b8282611fbd565b60018310156127ab5760405162461bcd60e51b815260040180806020018281038252602881526020018061365e6028913960400191505060405180910390fd5b6127bc85838460e001516001612e81565b6127ca858386866000612f2a565b6127d48585613054565b612415828261257a565b806001600160a01b0316846001600160a01b0316141561282f5760405162461bcd60e51b815260040180806020018281038252602a81526020018061376a602a913960400191505060405180910390fd5b61283761347f565b61283f61347f565b6128498282611fbd565b6001600160a01b038616600090815260086020526040902080546128af576040805162461bcd60e51b8152602060048201526018602482015277111151d15391ce88115b5c1d1e481cdd185ad9481b1a5cdd60421b604482015290519081900360640190fd5b805464ffffffffff871610612908576040805162461bcd60e51b815260206004820152601a602482015279111151d15391ce881cdd185ad9525b99195e081a5b9d985b1a5960321b604482015290519081900360640190fd5b808664ffffffffff168154811061291b57fe5b600091825260209091200154600160d81b900461ffff1615612984576040805162461bcd60e51b815260206004820152601f60248201527f444547454e473a207374616b6520686173206265656e20756e6c6f636b656400604482015290519081900360640190fd5b808664ffffffffff168154811061299757fe5b60009182526020909120015464ffffffffff8681169116146129ea5760405162461bcd60e51b81526004018080602001828103825260218152602001806135b96021913960400191505060405180910390fd5b6129f26134cb565b612a19828864ffffffffff1681548110612a0857fe5b90600052602060002001878361203d565b612a2a88858660e001516001612e81565b612a3b828864ffffffffff1661241c565b60008460c001805160010164ffffffffff16908164ffffffffff168152509050612aa260086000886001600160a01b03166001600160a01b031681526020019081526020016000208284602001518560400151866060015187608001518860c00151613150565b612aac858561257a565b505050505050505050565b600062015180600454420381612ac957fe5b04905090565b604080514264ffffffffff9081166dffffffffffffffffff0000000000602889901b161768ffffffffffffffffff60701b607088901b16176001600160b81b031960b887901b161782526001600160481b038416602083015282513393918916926001600160a01b038b16927fd824970a2cf19cc2b630c87ce5b00f67301cac3ac60513d027c7a39129f93b4692918290030190a4505050505050565b80518254602083015160408401516060850151608086015160a087015160c09097015164ffffffffff1990951664ffffffffff909616959095176dffffffffffffffffff00000000001916600160281b6001600160481b03948516021768ffffffffffffffffff60701b1916600160701b93909216929092021761ffff60b81b1916600160b81b61ffff928316021761ffff60c81b1916600160c81b938216939093029290921761ffff60d81b1916600160d81b92909316919091029190911760ff60e81b1916600160e81b91151591909102179055565b61113233848484612e81565b815181526020808301519082015260408083015190820152606080830151908201526080808301519082015260a0808301519082015260c09182015164ffffffffff16910152565b60008083860160026001870104605a811015612cb25750605a5b85612cd1576000612cc38a8761327e565b919091029250612d33915050565b85811015612d0457878101612ce7868a83612d3d565b93506000612cf6878386612d3d565b85019550612d339350505050565b612d0f858984612d3d565b935085811415612d2157839250612d30565b8581850281612d2c57fe5b0492505b50505b9550959350505050565b6000825b82811015612d82576000818152600760205260409020546001600160481b03600160481b820481169116860281612d7457fe5b049190910190600101612d41565b509392505050565b6000848401600e01808411612da3576000915050612daf565b6102bc90840383020490505b949350505050565b6000806001831115612ddd57610e38831115612dd557610e38612dda565b600183035b90505b600066354a6ba7a18000851115612dfb5766354a6ba7a18000612dfd565b845b670214e8348c4f0000830261071c82020193509050680ecca2d59581a400008584025b0495945050505050565b8064ffffffffff167f9861fa0ed101659f7a59b4583fcc798dfa4f3b419bea371c8ee2ad0ffe13a31e60288464ffffffffff16901b4264ffffffffff16176040518082815260200191505060405180910390a25050565b81836080015110612e9157611837565b612e99613530565b8351612ea3610bb8565b0181526080840151612eb68583836132cb565b602085015115612ed65760208501805160a0870180519091019052600090525b60010183811015612ef157612eec8583836132cb565b612ed6565b612f01868660800151838661332e565b60808501819052602082015115612f2257612f2261dead83602001516122b9565b505050505050565b6115b3821115612f6b5760405162461bcd60e51b81526004018080602001828103825260298152602001806136af6029913960400191505060405180910390fd5b6000612f778484612db7565b905060008560400151620186a08387010281612f8f57fe5b04905080612fce5760405162461bcd60e51b815260040180806020018281038252603a815260200180613624603a913960400191505060405180910390fd5b600060018760e0015110612fe9578660e00151600101612fec565b60025b60c08801805160010164ffffffffff16908190526001600160a01b038a1660009081526008602052604090209192509061302b90828986868b8b613150565b613039898289868a8a6133af565b50506020860180519091019052505082519091019091525050565b6001600160a01b0382166130995760405162461bcd60e51b81526004018080602001828103825260218152602001806137006021913960400191505060405180910390fd5b6130dc81604051806060016040528060228152602001613575602291396001600160a01b038516600090815260208190526040902054919063ffffffff611edd16565b6001600160a01b038316600090815260208190526040902055600354613108908263ffffffff611f7416565b6003556040805182815290516000916001600160a01b038516917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9181900360200190a35050565b6040805160e08101825264ffffffffff97881681526001600160481b03968716602080830191825296881692820192835261ffff9586166060830190815294861660808301908152600060a0840181815295151560c085019081528c54600181018e559c8252989020925192909a0180549151935195519a519451975164ffffffffff1990921692909916919091176dffffffffffffffffff00000000001916600160281b928816929092029190911768ffffffffffffffffff60701b1916600160701b93909616929092029490941761ffff60b81b1916600160b81b968316969096029590951761ffff60c81b1916600160c81b938216939093029290921761ffff60d81b1916600160d81b91909216021760ff60e81b1916600160e81b92151592909202919091179055565b600061328861347f565b6132928482612c50565b61329a613530565b84516132a4610bb8565b0181526132b1828261344b565b60a0820180518501908190526040820151850281612e2057fe5b6132d5838361344b565b60409182015160009182526007602052919020805460a0909301516001600160481b03908116600160481b0268ffffffffffffffffff60481b199190931668ffffffffffffffffff199094169390931792909216179055565b836001600160a01b03167fb8d6eb541ded1720cc657b719f57abcb1fe4711cb7ead82751b135f5d94bc9448261336557600061336b565b600160481b5b69ffffffffffffffffffff1660388561ffff16901b60288761ffff16901b4264ffffffffff161717176040518082815260200191505060405180910390a250505050565b8464ffffffffff16866001600160a01b03167f14872dc760f33532684e68e1b6d5fd3f71ba7b07dee76bdb2b084f28b74233ef836133ee5760006133f4565b600160c81b5b6001600160d01b031660b88661ffff16901b6070886001600160481b0316901b60288a6001600160481b0316901b4264ffffffffff16171717176040518082815260200191505060405180910390a3505050505050565b80516269c5d19061271002046040820152606082015115610d07576060820180516040830180519091019052600090525050565b604051806101000160405280600081526020016000815260200160008152602001600081526020016000815260200160008152602001600064ffffffffff168152602001600081525090565b6040518060e00160405280600064ffffffffff16815260200160008152602001600081526020016000815260200160008152602001600081526020016000151581525090565b6040518061012001604052806009906020820280388339509192915050565b6040518060600160405280600081526020016000815260200160008152509056fe45524332303a207472616e7366657220746f20746865207a65726f206164647265737345524332303a206275726e20616d6f756e7420657863656564732062616c616e636545524332303a20617070726f766520746f20746865207a65726f2061646472657373444547454e473a207374616b654964506172616d206e6f7420696e207374616b6545524332303a207472616e7366657220616d6f756e7420657863656564732062616c616e6365444547454e473a204d6f7665206e6f7420617574686f72697a6564206279206f776e6572444547454e473a206e65775374616b6564486561727473206d757374206265206174206c65617374206d696e696d756d20736861726552617465444547454e473a206e65775374616b656444617973206c6f776572207468616e206d696e696d756d444547454e473a206265666f72654461792063616e6e6f7420626520696e2074686520667574757265444547454e473a206e65775374616b65644461797320686967686572207468616e206d6178696d756d45524332303a207472616e7366657220616d6f756e74206578636565647320616c6c6f77616e636545524332303a206275726e2066726f6d20746865207a65726f206164647265737345524332303a207472616e736665722066726f6d20746865207a65726f206164647265737345524332303a20617070726f76652066726f6d20746865207a65726f2061646472657373596f752063616e2774206d6f76652061207374616b6520746f207468652073616d65206164647265737345524332303a2064656372656173656420616c6c6f77616e63652062656c6f77207a65726fa265627a7a72315820514ea73f5a51a468ef89e104dcea34911f01ea36b1c28f1bb98ac0c1d6f7ecab64736f6c634300050d0032

Deployed ByteCode

0x6080604052600436106102255760003560e01c806370a0823111610123578063bddb279c116100ab578063dd62ed3e1161006f578063dd62ed3e14610a1c578063e46895d614610a57578063e742806a14610ab6578063f04b5fa014610aef578063fe575a8714610b3d57610225565b8063bddb279c146108af578063bde949e8146108c4578063c312452514610916578063cd4b39c81461097f578063d1c243e6146109d157610225565b806395d89b41116100f257806395d89b41146107e057806396a1521e146107f5578063a457c2d714610828578063a9059cbb14610861578063b11c699d1461089a57610225565b806370a08231146106f65780637b0472f0146107295780638f1c65c01461075957806390de68711461078357610225565b8063343009a2116101b15780634bbb22de116101755780634bbb22de146105bb5780635c9302c91461060657806365cf71b21461061b5780636a210a0e146106615780636ac3f2bd146106e157610225565b8063343009a2146104bc57806339509351146104f35780633a70a5ca1461052c5780633c09cfc614610541578063455a43961461058057610225565b806323b872dd116101f857806323b872dd146103565780632500affc146103995780632607443b146103d2578063313ce5671461045e57806333060d901461048957610225565b806304a20f091461022757806306fdde0314610258578063095ea7b3146102e257806318160ddd1461032f575b005b34801561023357600080fd5b5061023c610b70565b604080516001600160a01b039092168252519081900360200190f35b34801561026457600080fd5b5061026d610b76565b6040805160208082528351818301528351919283929083019185019080838360005b838110156102a757818101518382015260200161028f565b50505050905090810190601f1680156102d45780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b3480156102ee57600080fd5b5061031b6004803603604081101561030557600080fd5b506001600160a01b038135169060200135610b9b565b604080519115158252519081900360200190f35b34801561033b57600080fd5b50610344610bb8565b60408051918252519081900360200190f35b34801561036257600080fd5b5061031b6004803603606081101561037957600080fd5b506001600160a01b03813581169160208101359091169060400135610bbe565b3480156103a557600080fd5b50610225600480360360408110156103bc57600080fd5b506001600160a01b038135169060200135610c4b565b3480156103de57600080fd5b5061040b600480360360408110156103f557600080fd5b506001600160a01b038135169060200135610d0b565b6040805164ffffffffff90981688526001600160481b039687166020890152949095168685015261ffff928316606087015290821660808601521660a084015290151560c0830152519081900360e00190f35b34801561046a57600080fd5b50610473610d84565b6040805160ff9092168252519081900360200190f35b34801561049557600080fd5b50610344600480360360208110156104ac57600080fd5b50356001600160a01b0316610d89565b3480156104c857600080fd5b50610225600480360360408110156104df57600080fd5b508035906020013564ffffffffff16610da4565b3480156104ff57600080fd5b5061031b6004803603604081101561051657600080fd5b506001600160a01b038135169060200135611066565b34801561053857600080fd5b506103446110ba565b34801561054d57600080fd5b506102256004803603606081101561056457600080fd5b506001600160a01b0381351690602081013590604001356110d7565b34801561058c57600080fd5b50610225600480360360408110156105a357600080fd5b506001600160a01b0381351690602001351515611137565b3480156105c757600080fd5b50610225600480360360608110156105de57600080fd5b50803564ffffffffff90811691602081013590911690604001356001600160a01b03166111bb565b34801561061257600080fd5b506103446111c7565b34801561062757600080fd5b506102256004803603606081101561063e57600080fd5b5080356001600160a01b0316906020810135906040013564ffffffffff166111d6565b34801561066d57600080fd5b506106916004803603604081101561068457600080fd5b508035906020013561142f565b60408051602080825283518183015283519192839290830191858101910280838360005b838110156106cd5781810151838201526020016106b5565b505050509050019250505060405180910390f35b3480156106ed57600080fd5b5061034461154e565b34801561070257600080fd5b506103446004803603602081101561071957600080fd5b50356001600160a01b0316611556565b34801561073557600080fd5b506102256004803603604081101561074c57600080fd5b5080359060200135611571565b34801561076557600080fd5b506102256004803603602081101561077c57600080fd5b503561157c565b34801561078f57600080fd5b506107ad600480360360208110156107a657600080fd5b5035611657565b604080516001600160481b03948516815292909316602083015266ffffffffffffff168183015290519081900360600190f35b3480156107ec57600080fd5b5061026d611690565b34801561080157600080fd5b506102256004803603602081101561081857600080fd5b50356001600160a01b03166116b2565b34801561083457600080fd5b5061031b6004803603604081101561084b57600080fd5b506001600160a01b038135169060200135611723565b34801561086d57600080fd5b5061031b6004803603604081101561088457600080fd5b506001600160a01b038135169060200135611791565b3480156108a657600080fd5b5061023c6117a5565b3480156108bb57600080fd5b506103446117b4565b3480156108d057600080fd5b50610225600480360360808110156108e757600080fd5b506001600160a01b03813581169164ffffffffff602082013581169260408301359091169160600135166117ba565b34801561092257600080fd5b5061092b61183d565b604080516001600160481b039889168152968816602088015264ffffffffff95861687820152938716606087015261ffff909216608086015290941660a0840152921660c082015290519081900360e00190f35b34801561098b57600080fd5b50610225600480360360808110156109a257600080fd5b5064ffffffffff81358116916020810135909116906001600160a01b0360408201351690606001351515611890565b3480156109dd57600080fd5b5061031b600480360360608110156109f457600080fd5b5080356001600160a01b03908116916020810135909116906040013564ffffffffff16611a13565b348015610a2857600080fd5b5061034460048036036040811015610a3f57600080fd5b506001600160a01b0381358116916020013516611a39565b348015610a6357600080fd5b50610a9060048036036040811015610a7a57600080fd5b506001600160a01b038135169060200135611a64565b604080519485526020850193909352838301919091526060830152519081900360800190f35b348015610ac257600080fd5b5061022560048036036040811015610ad957600080fd5b506001600160a01b038135169060200135611afc565b348015610afb57600080fd5b50610b04611b56565b604051808261012080838360005b83811015610b2a578181015183820152602001610b12565b5050505090500191505060405180910390f35b348015610b4957600080fd5b5061031b60048036036020811015610b6057600080fd5b50356001600160a01b0316611bf0565b61dead81565b60405180604001604052806009815260200168111959d95b8811dbd960ba1b81525081565b6000610baf610ba8611c05565b8484611c09565b50600192915050565b60035490565b6000610bcb848484611cf5565b610c4184610bd7611c05565b610c3c856040518060600160405280602881526020016136d8602891396001600160a01b038a16600090815260016020526040812090610c15611c05565b6001600160a01b03168152602081019190915260400160002054919063ffffffff611edd16565b611c09565b5060019392505050565b600a546001600160a01b03163314610c9b576040805162461bcd60e51b815260206004820152600e60248201526d139bdd08185d5d1a1bdc9a5e995960921b604482015290519081900360640190fd5b80600b541015610ce6576040805162461bcd60e51b81526020600482015260116024820152704e6f7420656e6f75676820737570706c7960781b604482015290519081900360640190fd5b600b54610cf9908263ffffffff611f7416565b600b55610d07308383611cf5565b5050565b60086020528160005260406000208181548110610d2457fe5b60009182526020909120015464ffffffffff811692506001600160481b03600160281b820481169250600160701b8204169061ffff600160b81b8204811691600160c81b8104821691600160d81b8204169060ff600160e81b9091041687565b600881565b6001600160a01b031660009081526008602052604090205490565b610dac61347f565b610db461347f565b610dbe8282611fbd565b3360009081526008602052604090208054610e1b576040805162461bcd60e51b8152602060048201526018602482015277111151d15391ce88115b5c1d1e481cdd185ad9481b1a5cdd60421b604482015290519081900360640190fd5b80548510610e6d576040805162461bcd60e51b815260206004820152601a602482015279111151d15391ce881cdd185ad9525b99195e081a5b9d985b1a5960321b604482015290519081900360640190fd5b610e756134cb565b610e95828781548110610e8457fe5b90600052602060002001868361203d565b610e9e846120fa565b60a0810151606082015160e0860151600092151591839182918291829111610f7c578415610ed25786608001519550610f62565b610edc8a8861210d565b86606001518a60e001510395508660800151861115610f015786608001519550610f62565b61015e861015610f62578660c0015115610f62576040805162461bcd60e51b815260206004820152601f60248201527f444547454e473a204175746f2d7374616b65207374696c6c206c6f636b656400604482015290519081900360640190fd5b610f6d8a888861212b565b92965090945092509050610fec565b8660c0015115610fd3576040805162461bcd60e51b815260206004820152601f60248201527f444547454e473a204175746f2d7374616b65207374696c6c206c6f636b656400604482015290519081900360640190fd5b60408701516020808c0180519290920390915287015193505b6110038b8860200151896040015186868b8b6121ce565b8015801590611010575084155b1561101f5761101f8a82612290565b831561103a5761102f33856122b9565b61103a8a88866123a9565b60208701518a51038a5261104e888d61241c565b6110588a8a61257a565b505050505050505050505050565b6000610baf611073611c05565b84610c3c8560016000611084611c05565b6001600160a01b03908116825260208083019390935260409182016000908120918c16815292529020549063ffffffff6126f716565b6005546000906001600160481b03166110d1610bb8565b01905090565b600a546001600160a01b03163314611127576040805162461bcd60e51b815260206004820152600e60248201526d139bdd08185d5d1a1bdc9a5e995960921b604482015290519081900360640190fd5b611132838383612751565b505050565b736c12fd2a0fa89639028d04293051598c8aad5d113314611190576040805162461bcd60e51b815260206004820152600e60248201526d139bdd08185d5d1a1bdc9a5e995960921b604482015290519081900360640190fd5b6001600160a01b03919091166000908152600260205260409020805460ff1916911515919091179055565b611132338484846127de565b60006111d1612ab7565b905090565b6111de61347f565b6111e661347f565b6111f08282611fbd565b6001600160a01b038516600090815260086020526040902054611255576040805162461bcd60e51b8152602060048201526018602482015277111151d15391ce88115b5c1d1e481cdd185ad9481b1a5cdd60421b604482015290519081900360640190fd5b6001600160a01b03851660009081526008602052604090205484106112be576040805162461bcd60e51b815260206004820152601a602482015279111151d15391ce881cdd185ad9525b99195e081a5b9d985b1a5960321b604482015290519081900360640190fd5b6001600160a01b03851660009081526008602052604081208054869081106112e257fe5b9060005260206000200190506112f66134cb565b61130182868361203d565b80608001518160600151018460e001511015611364576040805162461bcd60e51b815260206004820152601e60248201527f444547454e473a205374616b65206e6f742066756c6c79207365727665640000604482015290519081900360640190fd5b60a0810151156113bb576040805162461bcd60e51b815260206004820152601e60248201527f444547454e473a205374616b6520616c726561647920756e6c6f636b65640000604482015290519081900360640190fd5b6113c4846120fa565b6113ce848261210d565b60008060006113e28785866080015161212b565b935093509350506113ff8a89866020015187604001518787612acf565b801561140f5761140f8782612290565b6114198585612b6c565b611423878761257a565b50505050505050505050565b60608183108015611446575060065461ffff168211155b61148f576040805162461bcd60e51b8152602060048201526015602482015274111151d15391ce881c985b99d9481a5b9d985b1a59605a1b604482015290519081900360640190fd5b8282036040519080825280602002602001820160405280156114bb578160200160208202803883390190505b509050826000805b5060008281526007602052604090205483516001830192600160901b830460901b66ffffffffffffff60901b16600160481b840460481b71ffffffffffffffffff00000000000000000016176001600160481b0390931692909217918291869190811061152c57fe5b6020026020010181815250508483600101935083106114c35750505092915050565b600454420390565b6001600160a01b031660009081526020819052604090205490565b610d07338383612751565b61158461347f565b61158c61347f565b6115968282611fbd565b60018260e00151116115e3576040805162461bcd60e51b8152602060048201526011602482015270444547454e473a20546f6f206561726c7960781b604482015290519081900360640190fd5b821561163d578160e0015183111561162c5760405162461bcd60e51b81526004018080602001828103825260298152602001806136866029913960400191505060405180910390fd5b61163882846000612c44565b61164d565b61164d828360e001516000612c44565b611132828261257a565b6007602052600090815260409020546001600160481b0380821691600160481b810490911690600160901b900466ffffffffffffff1683565b60405180604001604052806006815260200165444547454e4760d01b81525081565b600c546001600160a01b03163314611701576040805162461bcd60e51b815260206004820152600d60248201526c2bb937b7339039b2b73232b91760991b604482015290519081900360640190fd5b600a80546001600160a01b0319166001600160a01b0392909216919091179055565b6000610baf611730611c05565b84610c3c85604051806060016040528060258152602001613794602591396001600061175a611c05565b6001600160a01b03908116825260208083019390935260409182016000908120918d1681529252902054919063ffffffff611edd16565b6000610baf61179e611c05565b8484611cf5565b600a546001600160a01b031681565b600b5481565b6001600160a01b0384166000908152600960209081526040808320338452825280832064ffffffffff8616845290915290205460ff1661182b5760405162461bcd60e51b81526004018080602001828103825260248152602001806136006024913960400191505060405180910390fd5b611837848484846127de565b50505050565b6005546006546001600160481b0380831692600160481b810482169264ffffffffff600160901b8304811693600160b81b90930483169261ffff83169262010000810490911691600160581b9091041687565b61189861347f565b6118a061347f565b6118aa8282611fbd565b3360009081526008602052604090208054611907576040805162461bcd60e51b8152602060048201526018602482015277111151d15391ce88115b5c1d1e481cdd185ad9481b1a5cdd60421b604482015290519081900360640190fd5b805464ffffffffff881610611960576040805162461bcd60e51b815260206004820152601a602482015279111151d15391ce881cdd185ad9525b99195e081a5b9d985b1a5960321b604482015290519081900360640190fd5b808764ffffffffff168154811061197357fe5b60009182526020909120015464ffffffffff8781169116146119c65760405162461bcd60e51b81526004018080602001828103825260218152602001806135b96021913960400191505060405180910390fd5b50503360009081526009602090815260408083206001600160a01b0396909616835294815284822064ffffffffff96909616825294909452509120805460ff191691151591909117905550565b600960209081526000938452604080852082529284528284209052825290205460ff1681565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b600080600080611a7261347f565b611a7a61347f565b611a848282611fbd565b6001600160a01b0388166000908152600860205260408120805489908110611aa857fe5b906000526020600020019050611abc6134cb565b8154611ad190839064ffffffffff168361203d565b606081015160e085015103611ae785838361212b565b929e919d509b50909950975050505050505050565b600a546001600160a01b03163314611b4c576040805162461bcd60e51b815260206004820152600e60248201526d139bdd08185d5d1a1bdc9a5e995960921b604482015290519081900360640190fd5b610d0782826122b9565b611b5e613511565b60408051610120810182526005546001600160481b038082168352600160481b82048116602084015264ffffffffff600160901b8304811694840194909452600160b81b9091048116606083015260065461ffff8116608084015262010000810490911660a0830152600160581b900490911660c08201524260e08201526101008101611be9610bb8565b9052905090565b60026020526000908152604090205460ff1681565b3390565b6001600160a01b038316611c4e5760405162461bcd60e51b81526004018080602001828103825260248152602001806137466024913960400191505060405180910390fd5b6001600160a01b038216611c935760405162461bcd60e51b81526004018080602001828103825260228152602001806135976022913960400191505060405180910390fd5b6001600160a01b03808416600081815260016020908152604080832094871680845294825291829020859055815185815291517f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259281900390910190a3505050565b6001600160a01b038316611d3a5760405162461bcd60e51b81526004018080602001828103825260258152602001806137216025913960400191505060405180910390fd5b6001600160a01b038216611d7f5760405162461bcd60e51b81526004018080602001828103825260238152602001806135526023913960400191505060405180910390fd5b6001600160a01b03821660009081526002602052604090205460ff16158015611dc157506001600160a01b03831660009081526002602052604090205460ff16155b611e0b576040805162461bcd60e51b81526020600482015260166024820152751059191c995cdcc81a5cc8189b1858dadb1a5cdd195960521b604482015290519081900360640190fd5b611e4e816040518060600160405280602681526020016135da602691396001600160a01b038616600090815260208190526040902054919063ffffffff611edd16565b6001600160a01b038085166000908152602081905260408082209390935590841681522054611e83908263ffffffff6126f716565b6001600160a01b038084166000818152602081815260409182902094909455805185815290519193928716927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef92918290030190a3505050565b60008184841115611f6c5760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b83811015611f31578181015183820152602001611f19565b50505050905090810190601f168015611f5e5780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b505050900390565b6000611fb683836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250611edd565b9392505050565b6005546001600160481b038082168452600160481b82048116602085015264ffffffffff600160901b830481166040860152600160b81b9092048116606085015260065461ffff8116608086015262010000810490911660a0850152600160581b90041660c083015261202e612ab7565b60e0830152610d078282612c50565b825464ffffffffff8381169116146120865760405162461bcd60e51b81526004018080602001828103825260218152602001806135b96021913960400191505060405180910390fd5b915464ffffffffff811683526001600160481b03600160281b820481166020850152600160701b820416604084015261ffff600160b81b820481166060850152600160c81b820481166080850152600160d81b82041660a084015260ff600160e81b90910416151560c09092019190915250565b61210a818260e001516001612c44565b50565b604081015160a080840180519290920390915260e090920151910152565b6000806000808560800151851015612169576121568787606001518860800151888a60400151612c98565b60208801518201955090935091506121a6565b604086015160608701516121809190878101612d3d565b92508286602001510193506121a3866060015187608001518860a0015187612d8a565b91505b81156121c557838211156121bd57506000926121c5565b509182900391805b93509350935093565b8664ffffffffff16336001600160a01b03167f72d9c5a7ab13846e08d9c838f9e866a1bb4a66a2fd3ba3c9e7da3cf9e394dfd760b8876001600160481b0316901b6070896001600160481b0316901b60288b6001600160481b0316901b4264ffffffffff1617171784612242576000612248565b600160581b5b6bffffffffffffffffffffffff1660488761ffff16901b886001600160481b03161717604051808381526020018281526020019250505060405180910390a350505050505050565b6002810480156122a6576122a661dead826122b9565b6060909201805192909103919091019052565b6001600160a01b038216612314576040805162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f206164647265737300604482015290519081900360640190fd5b600354612327908263ffffffff6126f716565b6003556001600160a01b038216600090815260208190526040902054612353908263ffffffff6126f716565b6001600160a01b0383166000818152602081815260408083209490945583518581529351929391927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9281900390910190a35050565b81602001518111156111325760006123c5828460800151612db7565b905060008360400151620186a083850102816123dd57fe5b04905064ffffffffff8111156123f5575064ffffffffff5b846040015181111561241557604085018190528351612415908290612e2a565b5050505050565b8154600019018181146125495782818154811061243557fe5b9060005260206000200183838154811061244b57fe5b6000918252602090912082549101805464ffffffffff90921664ffffffffff199092169190911780825582546dffffffffffffffffff000000000019909116600160281b918290046001600160481b0390811690920217808355835468ffffffffffffffffff60701b19909116600160701b918290049092160217808255825461ffff60b81b19909116600160b81b9182900461ffff90811690920217808355835461ffff60c81b19909116600160c81b91829004831690910217808355835461ffff60d81b19909116600160d81b918290049092160217808255915460ff60e81b19909216600160e81b9283900460ff1615159092029190911790555b8280548061255357fe5b600082815260209020810160001990810180546001600160f01b0319169055019055505050565b8051825114158061259357508060200151826020015114155b806125a657508060400151826040015114155b806125b957508060600151826060015114155b156126475781516005805460208501516040860151606087015168ffffffffffffffffff199093166001600160481b039586161768ffffffffffffffffff60481b1916600160481b928616929092029190911764ffffffffff60901b1916600160901b64ffffffffff90921691909102176001600160b81b0316600160b81b93909116929092029190911790555b8060800151826080015114158061266657508060a001518260a0015114155b8061268757508060c0015164ffffffffff168260c0015164ffffffffff1614155b15610d075760808201516006805460a085015160c086015164ffffffffff16600160581b0264ffffffffff60581b196001600160481b0390921662010000026affffffffffffffffff00001961ffff90961661ffff19909416939093179490941691909117169190911790555050565b600082820183811015611fb6576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b61275961347f565b61276161347f565b61276b8282611fbd565b60018310156127ab5760405162461bcd60e51b815260040180806020018281038252602881526020018061365e6028913960400191505060405180910390fd5b6127bc85838460e001516001612e81565b6127ca858386866000612f2a565b6127d48585613054565b612415828261257a565b806001600160a01b0316846001600160a01b0316141561282f5760405162461bcd60e51b815260040180806020018281038252602a81526020018061376a602a913960400191505060405180910390fd5b61283761347f565b61283f61347f565b6128498282611fbd565b6001600160a01b038616600090815260086020526040902080546128af576040805162461bcd60e51b8152602060048201526018602482015277111151d15391ce88115b5c1d1e481cdd185ad9481b1a5cdd60421b604482015290519081900360640190fd5b805464ffffffffff871610612908576040805162461bcd60e51b815260206004820152601a602482015279111151d15391ce881cdd185ad9525b99195e081a5b9d985b1a5960321b604482015290519081900360640190fd5b808664ffffffffff168154811061291b57fe5b600091825260209091200154600160d81b900461ffff1615612984576040805162461bcd60e51b815260206004820152601f60248201527f444547454e473a207374616b6520686173206265656e20756e6c6f636b656400604482015290519081900360640190fd5b808664ffffffffff168154811061299757fe5b60009182526020909120015464ffffffffff8681169116146129ea5760405162461bcd60e51b81526004018080602001828103825260218152602001806135b96021913960400191505060405180910390fd5b6129f26134cb565b612a19828864ffffffffff1681548110612a0857fe5b90600052602060002001878361203d565b612a2a88858660e001516001612e81565b612a3b828864ffffffffff1661241c565b60008460c001805160010164ffffffffff16908164ffffffffff168152509050612aa260086000886001600160a01b03166001600160a01b031681526020019081526020016000208284602001518560400151866060015187608001518860c00151613150565b612aac858561257a565b505050505050505050565b600062015180600454420381612ac957fe5b04905090565b604080514264ffffffffff9081166dffffffffffffffffff0000000000602889901b161768ffffffffffffffffff60701b607088901b16176001600160b81b031960b887901b161782526001600160481b038416602083015282513393918916926001600160a01b038b16927fd824970a2cf19cc2b630c87ce5b00f67301cac3ac60513d027c7a39129f93b4692918290030190a4505050505050565b80518254602083015160408401516060850151608086015160a087015160c09097015164ffffffffff1990951664ffffffffff909616959095176dffffffffffffffffff00000000001916600160281b6001600160481b03948516021768ffffffffffffffffff60701b1916600160701b93909216929092021761ffff60b81b1916600160b81b61ffff928316021761ffff60c81b1916600160c81b938216939093029290921761ffff60d81b1916600160d81b92909316919091029190911760ff60e81b1916600160e81b91151591909102179055565b61113233848484612e81565b815181526020808301519082015260408083015190820152606080830151908201526080808301519082015260a0808301519082015260c09182015164ffffffffff16910152565b60008083860160026001870104605a811015612cb25750605a5b85612cd1576000612cc38a8761327e565b919091029250612d33915050565b85811015612d0457878101612ce7868a83612d3d565b93506000612cf6878386612d3d565b85019550612d339350505050565b612d0f858984612d3d565b935085811415612d2157839250612d30565b8581850281612d2c57fe5b0492505b50505b9550959350505050565b6000825b82811015612d82576000818152600760205260409020546001600160481b03600160481b820481169116860281612d7457fe5b049190910190600101612d41565b509392505050565b6000848401600e01808411612da3576000915050612daf565b6102bc90840383020490505b949350505050565b6000806001831115612ddd57610e38831115612dd557610e38612dda565b600183035b90505b600066354a6ba7a18000851115612dfb5766354a6ba7a18000612dfd565b845b670214e8348c4f0000830261071c82020193509050680ecca2d59581a400008584025b0495945050505050565b8064ffffffffff167f9861fa0ed101659f7a59b4583fcc798dfa4f3b419bea371c8ee2ad0ffe13a31e60288464ffffffffff16901b4264ffffffffff16176040518082815260200191505060405180910390a25050565b81836080015110612e9157611837565b612e99613530565b8351612ea3610bb8565b0181526080840151612eb68583836132cb565b602085015115612ed65760208501805160a0870180519091019052600090525b60010183811015612ef157612eec8583836132cb565b612ed6565b612f01868660800151838661332e565b60808501819052602082015115612f2257612f2261dead83602001516122b9565b505050505050565b6115b3821115612f6b5760405162461bcd60e51b81526004018080602001828103825260298152602001806136af6029913960400191505060405180910390fd5b6000612f778484612db7565b905060008560400151620186a08387010281612f8f57fe5b04905080612fce5760405162461bcd60e51b815260040180806020018281038252603a815260200180613624603a913960400191505060405180910390fd5b600060018760e0015110612fe9578660e00151600101612fec565b60025b60c08801805160010164ffffffffff16908190526001600160a01b038a1660009081526008602052604090209192509061302b90828986868b8b613150565b613039898289868a8a6133af565b50506020860180519091019052505082519091019091525050565b6001600160a01b0382166130995760405162461bcd60e51b81526004018080602001828103825260218152602001806137006021913960400191505060405180910390fd5b6130dc81604051806060016040528060228152602001613575602291396001600160a01b038516600090815260208190526040902054919063ffffffff611edd16565b6001600160a01b038316600090815260208190526040902055600354613108908263ffffffff611f7416565b6003556040805182815290516000916001600160a01b038516917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9181900360200190a35050565b6040805160e08101825264ffffffffff97881681526001600160481b03968716602080830191825296881692820192835261ffff9586166060830190815294861660808301908152600060a0840181815295151560c085019081528c54600181018e559c8252989020925192909a0180549151935195519a519451975164ffffffffff1990921692909916919091176dffffffffffffffffff00000000001916600160281b928816929092029190911768ffffffffffffffffff60701b1916600160701b93909616929092029490941761ffff60b81b1916600160b81b968316969096029590951761ffff60c81b1916600160c81b938216939093029290921761ffff60d81b1916600160d81b91909216021760ff60e81b1916600160e81b92151592909202919091179055565b600061328861347f565b6132928482612c50565b61329a613530565b84516132a4610bb8565b0181526132b1828261344b565b60a0820180518501908190526040820151850281612e2057fe5b6132d5838361344b565b60409182015160009182526007602052919020805460a0909301516001600160481b03908116600160481b0268ffffffffffffffffff60481b199190931668ffffffffffffffffff199094169390931792909216179055565b836001600160a01b03167fb8d6eb541ded1720cc657b719f57abcb1fe4711cb7ead82751b135f5d94bc9448261336557600061336b565b600160481b5b69ffffffffffffffffffff1660388561ffff16901b60288761ffff16901b4264ffffffffff161717176040518082815260200191505060405180910390a250505050565b8464ffffffffff16866001600160a01b03167f14872dc760f33532684e68e1b6d5fd3f71ba7b07dee76bdb2b084f28b74233ef836133ee5760006133f4565b600160c81b5b6001600160d01b031660b88661ffff16901b6070886001600160481b0316901b60288a6001600160481b0316901b4264ffffffffff16171717176040518082815260200191505060405180910390a3505050505050565b80516269c5d19061271002046040820152606082015115610d07576060820180516040830180519091019052600090525050565b604051806101000160405280600081526020016000815260200160008152602001600081526020016000815260200160008152602001600064ffffffffff168152602001600081525090565b6040518060e00160405280600064ffffffffff16815260200160008152602001600081526020016000815260200160008152602001600081526020016000151581525090565b6040518061012001604052806009906020820280388339509192915050565b6040518060600160405280600081526020016000815260200160008152509056fe45524332303a207472616e7366657220746f20746865207a65726f206164647265737345524332303a206275726e20616d6f756e7420657863656564732062616c616e636545524332303a20617070726f766520746f20746865207a65726f2061646472657373444547454e473a207374616b654964506172616d206e6f7420696e207374616b6545524332303a207472616e7366657220616d6f756e7420657863656564732062616c616e6365444547454e473a204d6f7665206e6f7420617574686f72697a6564206279206f776e6572444547454e473a206e65775374616b6564486561727473206d757374206265206174206c65617374206d696e696d756d20736861726552617465444547454e473a206e65775374616b656444617973206c6f776572207468616e206d696e696d756d444547454e473a206265666f72654461792063616e6e6f7420626520696e2074686520667574757265444547454e473a206e65775374616b65644461797320686967686572207468616e206d6178696d756d45524332303a207472616e7366657220616d6f756e74206578636565647320616c6c6f77616e636545524332303a206275726e2066726f6d20746865207a65726f206164647265737345524332303a207472616e736665722066726f6d20746865207a65726f206164647265737345524332303a20617070726f76652066726f6d20746865207a65726f2061646472657373596f752063616e2774206d6f76652061207374616b6520746f207468652073616d65206164647265737345524332303a2064656372656173656420616c6c6f77616e63652062656c6f77207a65726fa265627a7a72315820514ea73f5a51a468ef89e104dcea34911f01ea36b1c28f1bb98ac0c1d6f7ecab64736f6c634300050d0032