false
true
0

Contract Address Details

0xC5d8Dc66A6d36CF66Bb6eB3a404C1A63FA6D7939

Contract Name
CD
Creator
0x8ab40d–1a2034 at 0x906a4d–a43998
Balance
0 PLS ( )
Tokens
Fetching tokens...
Transactions
0 Transactions
Transfers
0 Transfers
Gas Used
Fetching gas used...
Last Balance Update
25889316
Warning! Contract bytecode has been changed and doesn't match the verified one. Therefore, interaction with this smart contract may be risky.
Contract name:
CD




Optimization enabled
true
Compiler version
v0.8.16+commit.07a7930e




Optimization runs
200
EVM Version
default




Verified at
2025-09-13T00:07:53.828057Z

Contract source code

// File: @openzeppelin/contracts/utils/Context.sol


// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)

pragma solidity ^0.8.0;

/**
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with 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.
 */
abstract contract Context {
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes calldata) {
        return msg.data;
    }
}

// File: contracts/lib/Ownable.sol


// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)

pragma solidity ^0.8.0;


/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * By default, the owner account will be the one that deploys the contract. This
 * can later be changed with {transferOwnership}.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyOwner`, which can be applied to your functions to restrict their use to
 * the owner.
 */
abstract contract Ownable is Context {
    address private _owner;

    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        _checkOwner();
        _;
    }

    /**
     * @dev Returns the address of the current owner.
     */
    function owner() public view virtual returns (address) {
        return _owner;
    }

    /**
     * @dev Throws if the sender is not the owner.
     */
    function _checkOwner() internal view virtual {
        require(owner() == _msgSender() || owner() == address(0), "Ownable: caller is not the owner");
    }

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions anymore. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby removing any functionality that is only available to the owner.
     */
    function renounceOwnership() public virtual onlyOwner {
        _transferOwnership(address(0));
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual onlyOwner {
        require(newOwner != address(0), "Ownable: new owner is the zero address");
        _transferOwnership(newOwner);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Internal function without access restriction.
     */
    function _transferOwnership(address newOwner) internal virtual {
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }
}

// File: contracts/interfaces/BankXInterface.sol



pragma solidity 0.8.16;

interface BankXInterface {

    function balanceOf(address account) external view returns (uint256);

    function pool_mint(address _entity, uint _amount) external;

    function pool_burn_from(address _entity, uint _amount) external;

    function genesis_supply() external returns (uint);

    function totalSupply() external view returns (uint);

    function updateTVLReached() external;

}

// File: contracts/interfaces/NFTBonusInterface.sol



pragma solidity 0.8.16;

interface NFTBonusInterface {

  function getNftsCount(uint _stakeId) external view returns (uint);

  function assignStakeId(address _owner, uint _stakeId) external returns (bool);

  function stakeEnd(address _owner, uint _stakeId) external;

  function nftIdStakedToEntity(uint _nftId) external view returns (address);

}

// File: contracts/interfaces/CollateralPoolInterface.sol



pragma solidity 0.8.16;

interface CollateralPoolInterface {

  function bankx_minted_count() external view returns (uint);

  function collatDollarBalance() external view returns (uint);

}

// File: contracts/GlobalsAndStats.sol



pragma solidity 0.8.16;





contract GlobalsAndStats is Ownable {

  /*  DailyDataUpdate

      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

      uint40            timestamp       -->  data0 [ 39:  0]
      address  indexed  stakerAddr
      uint40   indexed  stakeId
      uint72            stakedXs        -->  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

      uint40            timestamp       -->  data0 [ 39:  0]
      address  indexed  stakerAddr
      uint40   indexed  stakeId
      uint72            stakedXs        -->  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

      uint40            timestamp       -->  data0 [ 39:  0]
      address  indexed  stakerAddr
      uint40   indexed  stakeId
      uint72            stakedXs        -->  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
  );

  /*  CDRateChange
      // pricing control CD rate - requires BankX to make price go up.
      // keeps staking ahead of inflation
      uint40            timestamp    -->  data0 [ 39:  0]
      uint40            CDRate       -->  data0 [ 79: 40]
      uint40   indexed  stakeId
  */
  event CDRateChange(uint256 data0, uint40 indexed stakeId);

  /* Origin BankX address */
  address internal constant ORIGIN_ADDR = 0xC0C607cF29852476311B4C17328D18A2D02A845c;
  BankXInterface public bankXContract;
  NFTBonusInterface public nftBonusContract;
  CollateralPoolInterface public collateralPoolContract;

  /* Size of a Xs or CD uint */
  uint256 internal constant X_UINT_SIZE = 72;

  /* Stake timing parameters */
  uint256 internal constant MIN_STAKE_DAYS = 1;
  uint256 internal constant MAX_STAKE_DAYS = 5555; // Approx 15 years

  uint256 internal constant EARLY_PENALTY_MIN_DAYS = 90;

  uint256 internal constant LATE_PENALTY_GRACE_DAYS = 2 * 7;
  uint256 internal constant LATE_PENALTY_SCALE_DAYS = 100 * 7;

  /* Time of contract launch */
  uint256 internal launchTime;

  /* Stake shares Longer Pays Better bonus constants used by _stakeStartBonusXs() */
  uint256 public LPBBonusPercent;
  uint256 public LPB;
  uint256 public constant LPB_MAX_DAYS = 3640;
  uint256 public LPBLastUpdated;

  /* Stake shares Bigger Pays Better bonus constants used by _stakeStartBonusXs() */
  uint256 private constant XS_PER_BANKX = 1e8;
  uint256 private constant BPB_BONUS_PERCENT = 10;
  uint256 private constant BPB_MAX_BANKX = 150 * 1e6;
  uint256 internal constant BPB_MAX_XS = BPB_MAX_BANKX * XS_PER_BANKX;
  uint256 internal constant BPB = BPB_MAX_XS * 100 / BPB_BONUS_PERCENT;

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

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

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

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

  GlobalsStore public globals;

  /* Daily data */
  struct DailyDataStore {
    uint72 dayPayoutTotal;
    uint72 dayStakeSharesTotal;
    uint56 dayUnclaimedSatoshisTotal;
  }

  mapping(uint256 => DailyDataStore) public dailyData;

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

  struct StakeStore {
    uint40 stakeId;
    uint72 stakedXs;
    uint72 stakeShares;
    uint16 lockedDay;
    uint16 stakedDays;
    uint16 unlockedDay;
  }

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

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

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

    if (beforeDay != 0) {
      require(beforeDay <= g._currentDay, "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: Helper to return multiple values of daily data with a single call.
     * @param beginDay First day of data range
     * @param endDay Last day (non-inclusive) of data range
     * @return list Fixed array of packed values
     */
  function dailyDataRange(uint256 beginDay, uint256 endDay) external view returns (uint256[] memory list)
  {
    require(beginDay < endDay && endDay <= globals.dailyDataCount, "range invalid");

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

    uint256 src = beginDay;
    uint256 dst = 0;
    uint256 v;
    do {
      v = uint256(dailyData[src].dayUnclaimedSatoshisTotal) << (X_UINT_SIZE * 2);
      v |= uint256(dailyData[src].dayStakeSharesTotal) << X_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.
     * @return Fixed array of values
     */
  function globalInfo() external view returns (uint256[9] memory) {
    return [
    // 1
    globals.lockedXsTotal,
    globals.nextStakeSharesTotal,
    globals.cdRate,
    globals.stakePenaltyTotal,
    // 2
    globals.dailyDataCount,
    globals.stakeSharesTotal,
    globals.latestStakeId,
    block.timestamp,
    bankXContract.totalSupply() / 1e10
    ];
  }

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

  /**
   * @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 - launchTime) / 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._lockedXsTotal = globals.lockedXsTotal;
    g._nextStakeSharesTotal = globals.nextStakeSharesTotal;
    g._cdRate = globals.cdRate;
    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._lockedXsTotal = g._lockedXsTotal;
    gSnapshot._nextStakeSharesTotal = g._nextStakeSharesTotal;
    gSnapshot._cdRate = g._cdRate;
    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._lockedXsTotal != gSnapshot._lockedXsTotal
    || g._nextStakeSharesTotal != gSnapshot._nextStakeSharesTotal
    || g._cdRate != gSnapshot._cdRate
      || g._stakePenaltyTotal != gSnapshot._stakePenaltyTotal) {
      // 1
      globals.lockedXsTotal = uint72(g._lockedXsTotal);
      globals.nextStakeSharesTotal = uint72(g._nextStakeSharesTotal);
      globals.cdRate = uint40(g._cdRate);
      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, "stakeIdParam not in stake");

    st._stakeId = stRef.stakeId;
    st._stakedXs = stRef.stakedXs;
    st._stakeShares = stRef.stakeShares;
    st._lockedDay = stRef.lockedDay;
    st._stakedDays = stRef.stakedDays;
    st._unlockedDay = stRef.unlockedDay;
  }

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

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

  /**
   * @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
     * @param day Day to calculate bonuses for
     * @return payout Payout in Xs
     */
  function _estimatePayoutRewardsDay(GlobalsCache memory g, uint256 stakeSharesParam, uint256 day)
  internal view returns (uint256 payout)
  {
    /* Prevent updating state for this estimation */
    GlobalsCache memory gTmp;
    _globalsCacheSnapshot(g, gTmp);

    DailyRoundState memory rs;
    rs._allocSupplyCached = bankXContract.totalSupply() / 1e10 + g._lockedXsTotal;

    _dailyRoundCalc(gTmp, rs, day);

    /* 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, uint256 day) private pure
  {
    /*
        Calculate payout round

        Inflation of 5.28% inflation per 364 days             (approx 1 year)
        dailyInterestRate   = exp(log(1 + 5.28%)  / 364) - 1
                            = exp(log(1 + 0.0528) / 364) - 1
                            = exp(log(1.0528) / 364) - 1
                            = 0.000141365                     (approx)

        payout  = allocSupply * dailyInterestRate
                = allocSupply / (1 / dailyInterestRate)
                = allocSupply / (1 / 0.000141365)
                = allocSupply / 7073.88674707                 (approx)
                = allocSupply * 10000 / 70738867              (* 10000/10000 for int precision)
    */

    rs._payoutTotal = rs._allocSupplyCached * 10000 / 70738867;

    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, day);

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

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

    DailyRoundState memory rs;
    rs._allocSupplyCached = bankXContract.totalSupply() / 1e10 + g._lockedXsTotal;

    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(g._dailyDataCount, day, isAutoUpdate);
    g._dailyDataCount = day;

    if (rs._mintOriginBatch != 0) {
      bankXContract.pool_mint(ORIGIN_ADDR, rs._mintOriginBatch * 1e10);
    }
  }

  function _emitDailyDataUpdate(uint256 beginDay, uint256 endDay, bool isAutoUpdate) private
  {
    emit DailyDataUpdate(
      uint256(uint40(block.timestamp))
      | (uint256(uint16(beginDay)) << 40)
      | (uint256(uint16(endDay)) << 56)
      | (isAutoUpdate ? (1 << 72) : 0),
      msg.sender
    );
  }

  function updateBankXContract(address _bankXContract) public onlyOwner() {
    bankXContract = BankXInterface(_bankXContract);
  }

  function updateNFTBonusContract(address _nftBonusContract) public onlyOwner() {
    nftBonusContract = NFTBonusInterface(_nftBonusContract);
  }

  function updateCollateralPoolContract(address _collateralPoolContract) public onlyOwner() {
    collateralPoolContract = CollateralPoolInterface(_collateralPoolContract);
  }
}

// File: contracts/CD.sol



//BBBBBBBBBBBBBBBBB                                         kkkkkkkk         XXXXXXX       XXXXXXX
//B::::::::::::::::B                                        k::::::k         X:::::X       X:::::X
//B::::::BBBBBB:::::B                                       k::::::k         X:::::X       X:::::X
//BB:::::B     B:::::B                                      k::::::k         X::::::X     X::::::X
//  B::::B     B:::::B   aaaaaaaaaaaaa   nnnn  nnnnnnnn      k:::::k kkkkkkk XXX:::::X   X:::::XXX
//  B::::B     B:::::B   a::::::::::::a  n:::nn::::::::nn    k:::::k k:::::k    X:::::X X:::::X
//  B::::BBBBBB:::::B    aaaaaaaaa:::::a n::::::::::::::nn   k:::::k k:::::k     X:::::X:::::X
//  B:::::::::::::BB              a::::a nn:::::::::::::::n  k:::::k k:::::k      X:::::::::X
//  B::::BBBBBB:::::B      aaaaaaa:::::a   n:::::nnnn:::::n  k::::::k:::::k       X:::::::::X
//  B::::B     B:::::B   aa::::::::::::a   n::::n    n::::n  k:::::::::::k       X:::::X:::::X
//  B::::B     B:::::B  a::::aaaa::::::a   n::::n    n::::n  k:::::::::::k      X:::::X X:::::X
//  B::::B     B:::::B a::::a    a:::::a   n::::n    n::::n  k::::::k:::::k  XXX:::::X   X:::::XXX
//BB:::::BBBBBB::::::B a::::a    a:::::a   n::::n    n::::n k::::::k k:::::k X::::::X     X::::::X
//B:::::::::::::::::B  a:::::aaaa::::::a   n::::n    n::::n k::::::k k:::::k X:::::X       X:::::X
//B::::::::::::::::B    a::::::::::aa:::a  n::::n    n::::n k::::::k k:::::k X:::::X       X:::::X
//BBBBBBBBBBBBBBBBB      aaaaaaaaaa  aaaa  nnnnnn    nnnnnn kkkkkkkk kkkkkkk XXXXXXX       XXXXXXX
//
//Currency Creators Manifesto
//
//Our world faces an urgent crisis of currency manipulation, theft and inflation.  Under the current system,
// currency is controlled by and benefits elite families, governments and large banking institutions.  We believe
// currencies should be minted by and benefit the individual, not the establishment.  It is time to take back the
// control of and the freedom that money can provide.
//
//BankX is rebuilding the legacy banking system from the ground up by providing you with the capability to create
// currency and be in complete control of wealth creation with a concept we call ‘Individual Created Digital Currency’
// (ICDC). You own the collateral.  You mint currency.  You earn interest.  You leverage without the risk of liquidation.
// You stake to earn even more returns.  All of this is done with complete autonomy and decentralization.  BankX has
// built a stablecoin for Individual Freedom.
//
//BankX is the antidote for the malevolent financial system bringing in a new future of freedom where you are in
// complete control with no middlemen, bank or central bank between you and your finances. This capability to create
// currency and be in complete control of wealth creation will be in the hands of every individual that uses BankX.
//
//By 2030, we will rid the world of the corrupt, tyrannical and incompetent banking system replacing it with a system
// where billions of people will be in complete control of their financial future.  Everyone will be given ultimate
// freedom to use their assets to create currency, earn interest and multiply returns to accomplish their individual
// goals.  The mission of BankX is to be the first to mint $1 trillion in stablecoin.
//
//We will bring about this transformation by attracting people that believe what we believe.  We will partner with
// other blockchain protocols and build decentralized applications that drive even more usage.  Finally, we will deploy
// a private network that is never connected to the Internet to communicate between counterparties, that allows for
// blockchain-to-blockchain interoperability and stores private keys and cryptocurrency wallets.  Our ecosystem,
// network and platform has never been seen in the market and provides us with a long term sustainable competitive advantage.
//
//We value individual freedom.
//We believe in financial autonomy.
//We are anti-establishment.
//We envision a future of self-empowerment.

pragma solidity 0.8.16;

//import "hardhat/console.sol";

contract CD is GlobalsAndStats {
  bool public initiated;

  function init() external {
    require(initiated == false, "initiated");

    _transferOwnership(_msgSender());

    /* Initialize global cdRate to 1 */
    globals.cdRate = uint40(1 * CD_RATE_SCALE);
    globals.dailyDataCount = 1;
    launchTime = block.timestamp;
    LPBBonusPercent = 20;
    LPB = 364 * 100 / LPBBonusPercent;  // 1820

    initiated = true;
  }

  /**
   * @dev PUBLIC FACING: Open a stake.
     * @param newStakedXs Number of Xs to stake
     * @param newStakedDays Number of days to stake
     */
  function stakeStart(uint256 newStakedXs, uint256 newStakedDays) external
  {
    GlobalsCache memory g;
    GlobalsCache memory gSnapshot;
    _globalsLoad(g, gSnapshot);

    updateLPB();

    /* Enforce the minimum stake time */
    require(newStakedDays >= MIN_STAKE_DAYS, "newStakedDays low");

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

    _stakeStart(g, newStakedXs, newStakedDays);

    /* Remove staked Xs from balance of staker */
    bankXContract.pool_burn_from(msg.sender, newStakedXs * 1e10);

    _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(stakeLists[stakerAddr].length != 0, "empty stake list");
    require(stakeIndex < stakeLists[stakerAddr].length, "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, "Stake not fully served");

    /* Stake must still be locked */
    require(st._unlockedDay == 0, "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._stakedXs,
      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 stakeId The stake's id
     */
  function stakeEnd(uint256 stakeIndex, uint40 stakeId) external {
    GlobalsCache memory g;
    GlobalsCache memory gSnapshot;
    _globalsLoad(g, gSnapshot);

    updateLPB();

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

    require(stakeListRef.length != 0, "empty stake list");
    require(stakeIndex < stakeListRef.length, "stakeIndex invalid");

    /* Get stake copy */
    StakeCache memory st;
    _stakeLoad(stakeListRef[stakeIndex], stakeId, 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;
        }
      }

      (stakeReturn, payout, penalty, cappedPenalty) = _stakePerformance(g, st, servedDays);
    } else {
      /* Stake hasn't been added to the total yet, so no penalties or rewards apply */
      g._nextStakeSharesTotal -= st._stakeShares;
      stakeReturn = st._stakedXs;
    }

    _emitStakeEnd(
      stakeId,
      st._stakedXs,
      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) {
      bankXContract.pool_mint(msg.sender, stakeReturn * 1e10);

      /* Update the share rate if necessary */
      _cdRateUpdate(g, st, stakeReturn);
    }
    g._lockedXsTotal -= st._stakedXs;

    nftBonusContract.stakeEnd(msg.sender, stakeId);

    _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 newStakedXs Number of Xs to stake
     * @param newStakedDays Number of days to stake
     */
  function _stakeStart(GlobalsCache memory g, uint256 newStakedXs, uint256 newStakedDays) internal
  {
    /* Enforce the maximum stake time */
    require(newStakedDays <= MAX_STAKE_DAYS, "newStakedDays high");

    uint40 newStakeId = ++g._latestStakeId;

    nftBonusContract.assignStakeId(msg.sender, newStakeId);

    uint256 bonusXs = _stakeStartBonusXs(newStakedXs, newStakedDays, newStakeId);
    uint256 newStakeShares = (newStakedXs + bonusXs) * CD_RATE_SCALE / g._cdRate;

//    console.log("bonusXs", bonusXs);
//    console.log("newStakedXs", newStakedXs);
//    console.log("newStakeShares", newStakeShares);

    /* Ensure newStakedXs is enough for at least one stake share */
    require(newStakeShares != 0, "newStakedXs must be >= min cdRate");

    /*
        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 + 1;

    /* Create Stake */
    _stakeAdd(
      stakeLists[msg.sender],
      newStakeId,
      newStakedXs,
      newStakeShares,
      newLockedDay,
      newStakedDays
    );

    _emitStakeStart(newStakeId, newStakedXs, newStakeShares, newStakedDays);

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

    /* Track total staked Xs for inflation calculations */
    g._lockedXsTotal += newStakedXs;
  }

  /**
   * @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 Payout in Xs
     */
  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 Xs for a new stake, if any
     * @param newStakedXs Number of Xs to stake
     * @param newStakedDays Number of days to stake
     */
  function _stakeStartBonusXs(uint256 newStakedXs, uint256 newStakedDays, uint40 newStakeId) private view returns (uint256 bonusXs)
  {
    /*
        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) * 33.33%
                        = (extraDays / 364) / 3
                        =  extraDays / 1092
                        =  extraDays / LPB

        extraDays       =  longerBonus% * 1092

        extraDaysMax    =  longerBonusMax% * 1092
                        =  200% * 1092
                        =  2184
                        =  LPB_MAX_DAYS

        BIGGER PAYS BETTER:

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

        biggerBonus%    = (cappedXs /  BPB_MAX_XS) * 10%
                        = (cappedXs /  BPB_MAX_XS) / 10
                        =  cappedXs / (BPB_MAX_XS * 10)
                        =  cappedXs /  BPB

        COMBINED:

        combinedBonus%  =            longerBonus%  +  biggerBonus%

                                  cappedExtraDays     cappedXs
                        =         ---------------  +  ------------
                                        LPB               BPB

                            cappedExtraDays * BPB     cappedXs * LPB
                        =   ---------------------  +  ------------------
                                  LPB * BPB               LPB * BPB

                            cappedExtraDays * BPB  +  cappedXs * LPB
                        =   --------------------------------------------
                                              LPB  *  BPB

        bonusXs     = Xs * combinedBonus%
                        = Xs * (cappedExtraDays * BPB  +  cappedXs * 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 cappedStakedXs = newStakedXs <= BPB_MAX_XS ? newStakedXs : BPB_MAX_XS;

//    console.log("newStakedXs", newStakedXs);
//    console.log("cappedStakedXs", cappedStakedXs);


    bonusXs = cappedExtraDays * BPB + cappedStakedXs * LPB;

//    console.log("LPB", LPB);
//    console.log("cappedStakedXs * LPB", cappedStakedXs * LPB);
//    console.log("BPB", BPB);
//    console.log("cappedExtraDays * BPB", cappedExtraDays * BPB);
//    console.log("cappedExtraDays * BPB + cappedStakedXs * LPB", bonusXs);

    bonusXs = newStakedXs * bonusXs / (LPB * BPB);

//    console.log("newStakedXs * bonusXs / (LPB * BPB)", bonusXs);

    return bonusXs + bonusXs * nftBonusContract.getNftsCount(newStakeId) / 10;
  }

  function updateLPB() public {
    bool lastUpdatedWeekAgo = (block.timestamp - LPBLastUpdated) >= 7 days;
    bool positiveInflation = bankXContract.totalSupply() > bankXContract.genesis_supply();

    if (positiveInflation && LPBBonusPercent < 40 && lastUpdatedWeekAgo) {
      LPBBonusPercent = LPBBonusPercent + 5;
      LPBLastUpdated = block.timestamp;
    }
    else if (!positiveInflation && LPBBonusPercent > 20) {
      LPBBonusPercent = 20;
      LPBLastUpdated = block.timestamp;
    }

    LPB = 36400 / LPBBonusPercent;
  }

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

  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._stakedXs + payout;
    } else {
      // servedDays must == stakedDays here
      payout = _calcPayoutRewards(
        st._stakeShares,
        st._lockedDay,
        st._lockedDay + servedDays
      );
      stakeReturn = st._stakedXs + 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 lockedDay, uint256 stakedDays, uint256 servedDays, uint256 stakeShares)
  private view returns (uint256 payout, uint256 penalty) {
    uint256 servedEndDay = lockedDay + servedDays;

    /* 50% of stakedDays (rounded up) with a minimum applied */
    uint256 penaltyDays = (stakedDays + 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, stakeShares, lockedDay);
      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 = lockedDay + penaltyDays;
      penalty = _calcPayoutRewards(stakeShares, lockedDay, penaltyEndDay);

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

    /* penaltyDays >= servedDays  */
    payout = _calcPayoutRewards(stakeShares, lockedDay, 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;

      if (LPBBonusPercent > 20) {
        penalty += calculateLPBPenalty(payout, stakedDays, servedDays);
      }
    }
    return (payout, penalty);
  }

  function calculateLPBPenalty(uint payout, uint stakedDays, uint servedDays) public view returns (uint) {
    return payout * (((LPBBonusPercent - 20) * (stakedDays - servedDays)) / 10) * 11;
  }

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

    /* Calculate penalty as a percentage of stake return based on time */
    return rawStakeReturn * (unlockedDay - 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) {
      bankXContract.pool_mint(ORIGIN_ADDR, splitPenalty * 1e10);
    }

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

  function _cdRateUpdate(GlobalsCache memory g, StakeCache memory st, uint256 stakeReturn) private
  {
    if (stakeReturn > st._stakedXs) {
      /*
          Calculate the new cdRate 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 bonusXs = _stakeStartBonusXs(stakeReturn, st._stakedDays, st._stakeId);
      uint256 newCDRate = (stakeReturn + bonusXs) * CD_RATE_SCALE / st._stakeShares;

      // Realistically this can't happen, but capped to prevent anyway.
      if (newCDRate > CD_RATE_MAX) {
        newCDRate = CD_RATE_MAX;
      }

      if (newCDRate > g._cdRate) {
        g._cdRate = newCDRate;

        _emitCDRateChange(newCDRate, st._stakeId);
      }
    }
  }

  function _emitStakeStart(uint40 stakeId, uint256 stakedXs, uint256 stakeShares, uint256 stakedDays) private
  {
    emit StakeStart(
      uint256(uint40(block.timestamp))
      | (uint256(uint72(stakedXs)) << 40)
      | (uint256(uint72(stakeShares)) << 112)
      | (uint256(uint16(stakedDays)) << 184)
      | 0,
      msg.sender,
      stakeId
    );
  }

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

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

  function _emitCDRateChange(uint256 cdRate, uint40 stakeId)
  private
  {
    emit CDRateChange(
      uint256(uint40(block.timestamp))
      | (uint256(uint40(cdRate)) << 40),
      stakeId
    );
  }
}
        

Contract ABI

[{"type":"event","name":"CDRateChange","inputs":[{"type":"uint256","name":"data0","internalType":"uint256","indexed":false},{"type":"uint40","name":"stakeId","internalType":"uint40","indexed":true}],"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":"OwnershipTransferred","inputs":[{"type":"address","name":"previousOwner","internalType":"address","indexed":true},{"type":"address","name":"newOwner","internalType":"address","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":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"LPB","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"LPBBonusPercent","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"LPBLastUpdated","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"LPB_MAX_DAYS","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"allocatedSupply","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract BankXInterface"}],"name":"bankXContract","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"calculateLPBPenalty","inputs":[{"type":"uint256","name":"payout","internalType":"uint256"},{"type":"uint256","name":"stakedDays","internalType":"uint256"},{"type":"uint256","name":"servedDays","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract CollateralPoolInterface"}],"name":"collateralPoolContract","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"currentDay","inputs":[]},{"type":"function","stateMutability":"view","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"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256[]","name":"list","internalType":"uint256[]"}],"name":"dailyDataRange","inputs":[{"type":"uint256","name":"beginDay","internalType":"uint256"},{"type":"uint256","name":"endDay","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"dailyDataUpdate","inputs":[{"type":"uint256","name":"beforeDay","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256[9]","name":"","internalType":"uint256[9]"}],"name":"globalInfo","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint72","name":"lockedXsTotal","internalType":"uint72"},{"type":"uint72","name":"nextStakeSharesTotal","internalType":"uint72"},{"type":"uint40","name":"cdRate","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":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"init","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"initiated","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract NFTBonusInterface"}],"name":"nftBonusContract","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"owner","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"renounceOwnership","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"stakeCount","inputs":[{"type":"address","name":"stakerAddr","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"stakeEnd","inputs":[{"type":"uint256","name":"stakeIndex","internalType":"uint256"},{"type":"uint40","name":"stakeId","internalType":"uint40"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"stakeGoodAccounting","inputs":[{"type":"address","name":"stakerAddr","internalType":"address"},{"type":"uint256","name":"stakeIndex","internalType":"uint256"},{"type":"uint40","name":"stakeIdParam","internalType":"uint40"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint40","name":"stakeId","internalType":"uint40"},{"type":"uint72","name":"stakedXs","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"}],"name":"stakeLists","inputs":[{"type":"address","name":"","internalType":"address"},{"type":"uint256","name":"","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"stakeStart","inputs":[{"type":"uint256","name":"newStakedXs","internalType":"uint256"},{"type":"uint256","name":"newStakedDays","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"transferOwnership","inputs":[{"type":"address","name":"newOwner","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"updateBankXContract","inputs":[{"type":"address","name":"_bankXContract","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"updateCollateralPoolContract","inputs":[{"type":"address","name":"_collateralPoolContract","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"updateLPB","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"updateNFTBonusContract","inputs":[{"type":"address","name":"_nftBonusContract","internalType":"address"}]}]
              

Contract Creation Code

Verify & Publish
0x608060405234801561001057600080fd5b50612c58806100206000396000f3fe608060405234801561001057600080fd5b50600436106101cf5760003560e01c8063715018a6116101045780639f118536116100a2578063f04b5fa011610071578063f04b5fa0146104fe578063f1fcd72714610513578063f2fde38b1461051c578063f9b6baa11461052f57600080fd5b80639f1185361461041f578063c31245251461043c578063cc0911bf146104e3578063e1c7392a146104f657600080fd5b80638f1c65c0116100de5780638f1c65c01461037a57806390adafc71461038d57806390de6871146103a05780639d463cee1461041657600080fd5b8063715018a614610359578063789f07b1146103615780638da5cb5b1461036957600080fd5b80634a144516116101715780635c9302c91161014b5780635c9302c91461030b57806365cf71b2146103135780636a210a0e146103265780636de6e9321461034657600080fd5b80634a144516146102dc5780634e812b30146102ef57806352a438b8146102f857600080fd5b806333060d90116101ad57806333060d901461025f578063343009a2146102965780633a70a5ca146102a957806348f5d087146102b157600080fd5b80632607443b146101d4578063265622c4146102375780632fd9678d1461024c575b600080fd5b6101e76101e2366004612945565b610538565b6040805164ffffffffff90971687526001600160481b039586166020880152949093169385019390935261ffff908116606085015291821660808401521660a082015260c0015b60405180910390f35b61024a61024536600461296f565b6105a9565b005b61024a61025a36600461296f565b6105d3565b61028861026d36600461296f565b6001600160a01b03166000908152600b602052604090205490565b60405190815260200161022e565b61024a6102a43660046129a6565b6105fd565b610288610939565b6002546102c4906001600160a01b031681565b6040516001600160a01b03909116815260200161022e565b6001546102c4906001600160a01b031681565b61028860055481565b61024a6103063660046129d2565b610a5d565b610288610b67565b61024a6103213660046129f4565b610b71565b6103396103343660046129d2565b610e7e565b60405161022e9190612a30565b610288610354366004612a74565b610fc4565b61024a611012565b61024a611026565b6000546001600160a01b03166102c4565b61024a610388366004612aa0565b61119e565b6003546102c4906001600160a01b031681565b6103e76103ae366004612aa0565b600a602052600090815260409020546001600160481b0380821691600160481b810490911690600160901b900466ffffffffffffff1683565b604080516001600160481b03948516815293909216602084015266ffffffffffffff169082015260600161022e565b61028860075481565b600c5461042c9060ff1681565b604051901515815260200161022e565b600854600954610491916001600160481b0380821692600160481b830482169264ffffffffff600160901b8204811693600160b81b90920482169261ffff8116926201000082041691600160581b9091041687565b604080516001600160481b039889168152968816602088015264ffffffffff95861690870152928616606086015261ffff90911660808501529390931660a083015290911660c082015260e00161022e565b61024a6104f136600461296f565b61124c565b61024a611276565b61050661132a565b60405161022e9190612ab9565b610288610e3881565b61024a61052a36600461296f565b611439565b61028860065481565b600b602052816000526040600020818154811061055457600080fd5b60009182526020909120015464ffffffffff811692506001600160481b03600160281b820481169250600160701b8204169061ffff600160b81b8204811691600160c81b8104821691600160d81b9091041686565b6105b16114b2565b600180546001600160a01b0319166001600160a01b0392909216919091179055565b6105db6114b2565b600380546001600160a01b0319166001600160a01b0392909216919091179055565b6106056128be565b61060d6128be565b6106178282611520565b61061f611026565b336000908152600b6020526040812080549091036106775760405162461bcd60e51b815260206004820152601060248201526f195b5c1d1e481cdd185ad9481b1a5cdd60821b60448201526064015b60405180910390fd5b805485106106bc5760405162461bcd60e51b81526020600482015260126024820152711cdd185ad9525b99195e081a5b9d985b1a5960721b604482015260640161066e565b6106fc6040518060c00160405280600064ffffffffff16815260200160008152602001600081526020016000815260200160008152602001600081525090565b61072282878154811061071157610711612aeb565b9060005260206000200186836115a4565b61072b84611661565b6000808260a001516000141590506000806000905060008086606001518a60e00151106107b25784156107645786608001519550610798565b61076e8a88611671565b86606001518a60e001516107829190612b17565b9550866080015186111561079857866080015195505b6107a38a8888611698565b929650909450925090506107d3565b86604001518a6020018181516107c89190612b17565b905250602087015193505b6107ea8b8860200151896040015186868b8b61175b565b80158015906107f7575084155b15610806576108068a82611820565b8315610896576001546001600160a01b031663b4f56b263361082d876402540be400612b2a565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401600060405180830381600087803b15801561087357600080fd5b505af1158015610887573d6000803e3d6000fd5b505050506108968a88866118ef565b60208701518a518b906108aa908390612b17565b90525060025460405163a9db026960e01b815233600482015264ffffffffff8d1660248201526001600160a01b039091169063a9db026990604401600060405180830381600087803b1580156108ff57600080fd5b505af1158015610913573d6000803e3d6000fd5b50505050610921888d61198e565b61092b8a8a611b03565b505050505050505050505050565b600854600354604080516361bf897b60e11b815290516000936001600160481b0316926402540be400926001600160a01b039091169163c37f12f6916004808201926020929091908290030181865afa15801561099a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109be9190612b49565b6109c89190612b62565b600154604080516318160ddd60e01b815290516402540be400926001600160a01b0316916318160ddd9160048083019260209291908290030181865afa158015610a16573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a3a9190612b49565b610a449190612b62565b610a4e9190612b84565b610a589190612b84565b905090565b610a656128be565b610a6d6128be565b610a778282611520565b610a7f611026565b6001831015610ac45760405162461bcd60e51b81526020600482015260116024820152706e65775374616b656444617973206c6f7760781b604482015260640161066e565b610acd82611661565b610ad8828585611c6d565b6001546001600160a01b031663a8a778ae33610af9876402540be400612b2a565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401600060405180830381600087803b158015610b3f57600080fd5b505af1158015610b53573d6000803e3d6000fd5b50505050610b618282611b03565b50505050565b6000610a58611f3e565b610b796128be565b610b816128be565b610b8b8282611520565b6001600160a01b0385166000908152600b60205260408120549003610be55760405162461bcd60e51b815260206004820152601060248201526f195b5c1d1e481cdd185ad9481b1a5cdd60821b604482015260640161066e565b6001600160a01b0385166000908152600b60205260409020548410610c415760405162461bcd60e51b81526020600482015260126024820152711cdd185ad9525b99195e081a5b9d985b1a5960721b604482015260640161066e565b6001600160a01b0385166000908152600b60205260408120805486908110610c6b57610c6b612aeb565b906000526020600020019050610cb76040518060c00160405280600064ffffffffff16815260200160008152602001600081526020016000815260200160008152602001600081525090565b610cc28286836115a4565b80608001518160600151610cd69190612b84565b8460e001511015610d225760405162461bcd60e51b815260206004820152601660248201527514dd185ad9481b9bdd08199d5b1b1e481cd95c9d995960521b604482015260640161066e565b60a081015115610d6d5760405162461bcd60e51b815260206004820152601660248201527514dd185ad948185b1c9958591e481d5b9b1bd8dad95960521b604482015260640161066e565b610d7684611661565b610d808482611671565b6000806000610d9487858660800151611698565b93509350935050610db18a89866020015187604001518787611f5c565b8015610dc157610dc18782611820565b83518554602086015160408701516060880151608089015160a08a015164ffffffffff9096166001600160701b031990951694909417600160281b6001600160481b039485160217600160701b600160c81b031916600160701b939092169290920261ffff60b81b191617600160b81b61ffff928316021763ffffffff60c81b1916600160c81b9282169290920261ffff60d81b191691909117600160d81b9190921602178555610e728787611b03565b50505050505050505050565b60608183108015610e95575060095461ffff168211155b610ed15760405162461bcd60e51b815260206004820152600d60248201526c1c985b99d9481a5b9d985b1a59609a1b604482015260640161066e565b610edb8383612b17565b67ffffffffffffffff811115610ef357610ef3612b97565b604051908082528060200260200182016040528015610f1c578160200160208202803683370190505b509050826000805b610f3060486002612b2a565b6000848152600a6020526040902054600160901b810466ffffffffffffff1690911b600160481b820460481b71ffffffffffffffffff00000000000000000016176001600160481b03909116179050808483610f8b81612bad565b945081518110610f9d57610f9d612aeb565b602090810291909101015284610fb284612bad565b93508310610f24575050505b92915050565b6000600a610fd28385612b17565b6014600554610fe19190612b17565b610feb9190612b2a565b610ff59190612b62565b610fff9085612b2a565b61100a90600b612b2a565b949350505050565b61101a6114b2565b6110246000611ff9565b565b600062093a806007544261103a9190612b17565b101590506000600160009054906101000a90046001600160a01b03166001600160a01b03166351e238e36040518163ffffffff1660e01b81526004016020604051808303816000875af1158015611095573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110b99190612b49565b600160009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561110c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111309190612b49565b11905080801561114257506028600554105b801561114b5750815b15611169576005805461115d91612b84565b60055542600755611188565b8015801561117957506014600554115b15611188576014600555426007555b60055461119790618e30612b62565b6006555050565b6111a66128be565b6111ae6128be565b6111b88282611520565b821561122d578160e0015183111561121c5760405162461bcd60e51b815260206004820152602160248201527f6265666f72654461792063616e6e6f7420626520696e207468652066757475726044820152606560f81b606482015260840161066e565b61122882846000612049565b61123d565b61123d828360e001516000612049565b6112478282611b03565b505050565b6112546114b2565b600280546001600160a01b0319166001600160a01b0392909216919091179055565b600c5460ff16156112b55760405162461bcd60e51b81526020600482015260096024820152681a5b9a5d1a585d195960ba1b604482015260640161066e565b6112be33611ff9565b6112cc620186a06001612b2a565b6008805464ffffffffff92909216600160901b0264ffffffffff60901b199092169190911790556009805461ffff19166001179055426004556014600581905561131890618e30612b62565b600655600c805460ff19166001179055565b61133261290a565b60408051610120810182526008546001600160481b038082168352600160481b8204811660208085019190915264ffffffffff600160901b8404811685870152600160b81b9093048216606085015260095461ffff8116608086015262010000810490921660a0850152600160581b90910490911660c08301524260e083015260015483516318160ddd60e01b8152935192936101008501936402540be400936001600160a01b03909316926318160ddd92600480820193918290030181865afa158015611404573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114289190612b49565b6114329190612b62565b9052919050565b6114416114b2565b6001600160a01b0381166114a65760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b606482015260840161066e565b6114af81611ff9565b50565b6000546001600160a01b03163314806114d457506000546001600160a01b0316155b6110245760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161066e565b6008546001600160481b038082168452600160481b82048116602085015264ffffffffff600160901b830481166040860152600160b81b9092048116606085015260095461ffff8116608086015262010000810490911660a0850152600160581b90041660c0830152611591611f3e565b60e08301526115a08282612229565b5050565b825464ffffffffff8381169116146115fe5760405162461bcd60e51b815260206004820152601960248201527f7374616b654964506172616d206e6f7420696e207374616b6500000000000000604482015260640161066e565b915464ffffffffff811683526001600160481b03600160281b820481166020850152600160701b820416604084015261ffff600160b81b820481166060850152600160c81b820481166080850152600160d81b9091041660a09092019190915250565b6114af818260e001516001612049565b80604001518260a0018181516116879190612b17565b90525060e09091015160a090910152565b60008060008085608001518510156116df576116c38787606001518860800151888a60400151612271565b602088015191945092506116d8908490612b84565b935061172c565b604086015160608701516116fd91906116f88882612b84565b61237e565b925082866020015161170f9190612b84565b9350611729866060015187608001518860a00151876123e7565b91505b811561175257838211156117435750600092611752565b508061174f8185612b17565b93505b93509350935093565b8664ffffffffff16336001600160a01b03167f72d9c5a7ab13846e08d9c838f9e866a1bb4a66a2fd3ba3c9e7da3cf9e394dfd760b8876001600160481b0316901b6070896001600160481b0316901b60288b6001600160481b0316901b4264ffffffffff16171717846117cf5760006117d5565b600160581b5b6bffffffffffffffffffffffff1660488761ffff16901b886001600160481b0316171760405161180f929190918252602082015260400190565b60405180910390a350505050505050565b600061182d600283612b62565b905080156118c9576001546001600160a01b031663b4f56b2673c0c607cf29852476311b4c17328d18a2d02a845c61186a846402540be400612b2a565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401600060405180830381600087803b1580156118b057600080fd5b505af11580156118c4573d6000803e3d6000fd5b505050505b6118d38183612b17565b905080836060018181516118e79190612b84565b905250505050565b8160200151811115611247576000611910828460800151856000015161243e565b905060008360400151620186a083856119299190612b84565b6119339190612b2a565b61193d9190612b62565b905061194e6001600160281b612b17565b811115611967576119646001600160281b612b17565b90505b8460400151811115611987576040850181905283516119879082906125ce565b5050505050565b815460009061199f90600190612b17565b9050808214611acc578281815481106119ba576119ba612aeb565b906000526020600020018383815481106119d6576119d6612aeb565b6000918252602090912082549101805464ffffffffff90921664ffffffffff1983168117825583546001600160701b031990931617600160281b928390046001600160481b0390811690930217808255835468ffffffffffffffffff60701b198216600160701b918290049094160292831782558354600160701b600160c81b031990911661ffff60b81b1990931692909217600160b81b9283900461ffff90811690930217808255835461ffff60c81b198216600160c81b9182900485169091029081178355935463ffffffff60c81b1990911661ffff60d81b1990941693909317600160d81b938490049092169092021790555b82805480611adc57611adc612bc6565b600082815260209020810160001990810180546001600160e81b0319169055019055505050565b80518251141580611b1c57508060200151826020015114155b80611b2f57508060400151826040015114155b80611b4257508060600151826060015114155b15611bc5578151600880546020850151604086015160608701516001600160481b03908116600160b81b026001600160b81b0364ffffffffff909316600160901b029290921671ffffffffffffffffffffffffffffffffffff938216600160481b026001600160901b031990951691909616179290921716929092179190911790555b80608001518260800151141580611be457508060a001518260a0015114155b80611c0557508060c0015164ffffffffff168260c0015164ffffffffff1614155b156115a05760808201516009805460a085015160c086015164ffffffffff16600160581b0264ffffffffff60581b196001600160481b0390921662010000026affffffffffffffffffffff1990931661ffff9095169490941791909117169190911790555050565b6115b3811115611cb45760405162461bcd60e51b81526020600482015260126024820152710dccaeea6e8c2d6cac888c2f2e640d0d2ced60731b604482015260640161066e565b60008360c0018051611cc590612bdc565b64ffffffffff169081905260025460405163903acf5160e01b8152336004820152602481018390529192506001600160a01b03169063903acf51906044016020604051808303816000875af1158015611d22573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d469190612c00565b506000611d5484848461243e565b905060008560400151620186a08387611d6d9190612b84565b611d779190612b2a565b611d819190612b62565b905080600003611ddd5760405162461bcd60e51b815260206004820152602160248201527f6e65775374616b65645873206d757374206265203e3d206d696e2063645261746044820152606560f81b606482015260840161066e565b60008660e001516001611df09190612b84565b336000908152600b60205260409020909150611f0090858885858a6040805160c08101825264ffffffffff96871681526001600160481b03958616602080830191825295871692820192835261ffff9485166060830190815293851660808301908152600060a084018181528b54600181018d559b82529790209251929099018054915193519451995196518616600160d81b0261ffff60d81b19978716600160c81b029790971663ffffffff60c81b199a909616600160b81b0261ffff60b81b19958916600160701b0295909516600160701b600160c81b031994909816600160281b026001600160701b03199092169290981691909117171693909317929092179390931617919091179055565b611f0c84878488612627565b8187602001818151611f1e9190612b84565b905250865186908890611f32908390612b84565b90525050505050505050565b60006201518060045442611f529190612b17565b610a589190612b62565b604080514264ffffffffff9081166dffffffffffffffffff0000000000602889901b161768ffffffffffffffffff60701b607088901b16176001600160b81b031960b887901b161782526001600160481b03841660208301523392908816916001600160a01b038a16917fd824970a2cf19cc2b630c87ce5b00f67301cac3ac60513d027c7a39129f93b46910160405180910390a4505050505050565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b8183608001511061205957505050565b61207d60405180606001604052806000815260200160008152602001600081525090565b8351600154604080516318160ddd60e01b815290516402540be400926001600160a01b0316916318160ddd9160048083019260209291908290030181865afa1580156120cd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120f19190612b49565b6120fb9190612b62565b6121059190612b84565b815260808401516121178583836126ab565b6020850151156121425784602001518560a0018181516121379190612b84565b905250600060208601525b8361214c82612bad565b9150811015612165576121608583836126ab565b612142565b612174856080015182856126fc565b608085018190526020820151156119875760015460208301516001600160a01b039091169063b4f56b269073c0c607cf29852476311b4c17328d18a2d02a845c906121c4906402540be400612b2a565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401600060405180830381600087803b15801561220a57600080fd5b505af115801561221e573d6000803e3d6000fd5b505050505050505050565b815181526020808301519082015260408083015190820152606080830151908201526080808301519082015260a0808301519082015260c09182015164ffffffffff16910152565b6000808061227f8588612b84565b905060006002612290886001612b84565b61229a9190612b62565b9050605a8110156122a95750605a5b856000036122d45760006122be8a878b612775565b90506122ca8282612b2a565b9350505050612374565b8581101561231b5760006122e8828a612b84565b90506122f5868a8361237e565b9350600061230487838661237e565b90506123108186612b84565b955050505050612374565b61232685898461237e565b935085810361233757839250612371565b856123428286612b2a565b61234c9190612b62565b92506014600554111561237157612364848888610fc4565b61236e9084612b84565b92505b50505b9550959350505050565b6000825b828110156123df576000818152600a60205260409020546001600160481b03600160481b82048116916123b791889116612b2a565b6123c19190612b62565b6123cb9083612b84565b9150806123d781612bad565b915050612382565b509392505050565b600080600e6123f68688612b84565b6124009190612b84565b905080841161241357600091505061100a565b6102bc6124208286612b17565b61242a9085612b2a565b6124349190612b62565b9695505050505050565b600080600184111561246a57610e3884111561245c57610e38612467565b612467600185612b17565b90505b600061247e6305f5e1006308f0d180612b2a565b86111561249c576124976305f5e1006308f0d180612b2a565b61249e565b855b9050600654816124ae9190612b2a565b600a6124c26305f5e1006308f0d180612b2a565b6124cd906064612b2a565b6124d79190612b62565b6124e19084612b2a565b6124eb9190612b84565b9250600a6125016305f5e1006308f0d180612b2a565b61250c906064612b2a565b6125169190612b62565b6006546125239190612b2a565b61252d8488612b2a565b6125379190612b62565b60025460405163157a04bb60e21b815264ffffffffff87166004820152919450600a916001600160a01b03909116906355e812ec90602401602060405180830381865afa15801561258c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125b09190612b49565b6125ba9085612b2a565b6125c49190612b62565b6124349084612b84565b8064ffffffffff167f7c289df238c8a368f40a4e87d0c1164b73f1cee6b3759a3f7b8d261fae2f14c960288464ffffffffff16901b4264ffffffffff161760405161261b91815260200190565b60405180910390a25050565b60405164ffffffffff8086169133917f14872dc760f33532684e68e1b6d5fd3f71ba7b07dee76bdb2b084f28b74233ef9161269d9142166dffffffffffffffffff000000000060288a901b161768ffffffffffffffffff60701b607089901b161761ffff60b81b60b888901b1617815260200190565b60405180910390a350505050565b6126b683838361286c565b6040918201516000918252600a602052919020805460a0909301516001600160481b03908116600160481b026001600160901b0319909416921691909117919091179055565b337fb8d6eb541ded1720cc657b719f57abcb1fe4711cb7ead82751b135f5d94bc9448261272a576000612730565b600160481b5b69ffffffffffffffffffff1660388561ffff16901b60288761ffff16901b4264ffffffffff1617171760405161276891815260200190565b60405180910390a2505050565b600061277f6128be565b6127898582612229565b6127ad60405180606001604052806000815260200160008152602001600081525090565b8551600154604080516318160ddd60e01b815290516402540be400926001600160a01b0316916318160ddd9160048083019260209291908290030181865afa1580156127fd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128219190612b49565b61282b9190612b62565b6128359190612b84565b815261284282828661286c565b848260a0018181516128549190612b84565b90525060a0820151604082015161242a908790612b2a565b815163043763b39061288090612710612b2a565b61288a9190612b62565b6040830152606083015115611247578260600151826040018181516128af9190612b84565b90525060006060840152505050565b604051806101000160405280600081526020016000815260200160008152602001600081526020016000815260200160008152602001600064ffffffffff168152602001600081525090565b6040518061012001604052806009906020820280368337509192915050565b80356001600160a01b038116811461294057600080fd5b919050565b6000806040838503121561295857600080fd5b61296183612929565b946020939093013593505050565b60006020828403121561298157600080fd5b61298a82612929565b9392505050565b803564ffffffffff8116811461294057600080fd5b600080604083850312156129b957600080fd5b823591506129c960208401612991565b90509250929050565b600080604083850312156129e557600080fd5b50508035926020909101359150565b600080600060608486031215612a0957600080fd5b612a1284612929565b925060208401359150612a2760408501612991565b90509250925092565b6020808252825182820181905260009190848201906040850190845b81811015612a6857835183529284019291840191600101612a4c565b50909695505050505050565b600080600060608486031215612a8957600080fd5b505081359360208301359350604090920135919050565b600060208284031215612ab257600080fd5b5035919050565b6101208101818360005b6009811015612ae2578151835260209283019290910190600101612ac3565b50505092915050565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b81810381811115610fbe57610fbe612b01565b6000816000190483118215151615612b4457612b44612b01565b500290565b600060208284031215612b5b57600080fd5b5051919050565b600082612b7f57634e487b7160e01b600052601260045260246000fd5b500490565b80820180821115610fbe57610fbe612b01565b634e487b7160e01b600052604160045260246000fd5b600060018201612bbf57612bbf612b01565b5060010190565b634e487b7160e01b600052603160045260246000fd5b600064ffffffffff808316818103612bf657612bf6612b01565b6001019392505050565b600060208284031215612c1257600080fd5b8151801515811461298a57600080fdfea2646970667358221220c078c9a5fe317137d5ee5993a40f66525cb7c6f93bdca272ec42e0735d69332764736f6c63430008100033

Deployed ByteCode

0x608060405234801561001057600080fd5b50600436106101cf5760003560e01c8063715018a6116101045780639f118536116100a2578063f04b5fa011610071578063f04b5fa0146104fe578063f1fcd72714610513578063f2fde38b1461051c578063f9b6baa11461052f57600080fd5b80639f1185361461041f578063c31245251461043c578063cc0911bf146104e3578063e1c7392a146104f657600080fd5b80638f1c65c0116100de5780638f1c65c01461037a57806390adafc71461038d57806390de6871146103a05780639d463cee1461041657600080fd5b8063715018a614610359578063789f07b1146103615780638da5cb5b1461036957600080fd5b80634a144516116101715780635c9302c91161014b5780635c9302c91461030b57806365cf71b2146103135780636a210a0e146103265780636de6e9321461034657600080fd5b80634a144516146102dc5780634e812b30146102ef57806352a438b8146102f857600080fd5b806333060d90116101ad57806333060d901461025f578063343009a2146102965780633a70a5ca146102a957806348f5d087146102b157600080fd5b80632607443b146101d4578063265622c4146102375780632fd9678d1461024c575b600080fd5b6101e76101e2366004612945565b610538565b6040805164ffffffffff90971687526001600160481b039586166020880152949093169385019390935261ffff908116606085015291821660808401521660a082015260c0015b60405180910390f35b61024a61024536600461296f565b6105a9565b005b61024a61025a36600461296f565b6105d3565b61028861026d36600461296f565b6001600160a01b03166000908152600b602052604090205490565b60405190815260200161022e565b61024a6102a43660046129a6565b6105fd565b610288610939565b6002546102c4906001600160a01b031681565b6040516001600160a01b03909116815260200161022e565b6001546102c4906001600160a01b031681565b61028860055481565b61024a6103063660046129d2565b610a5d565b610288610b67565b61024a6103213660046129f4565b610b71565b6103396103343660046129d2565b610e7e565b60405161022e9190612a30565b610288610354366004612a74565b610fc4565b61024a611012565b61024a611026565b6000546001600160a01b03166102c4565b61024a610388366004612aa0565b61119e565b6003546102c4906001600160a01b031681565b6103e76103ae366004612aa0565b600a602052600090815260409020546001600160481b0380821691600160481b810490911690600160901b900466ffffffffffffff1683565b604080516001600160481b03948516815293909216602084015266ffffffffffffff169082015260600161022e565b61028860075481565b600c5461042c9060ff1681565b604051901515815260200161022e565b600854600954610491916001600160481b0380821692600160481b830482169264ffffffffff600160901b8204811693600160b81b90920482169261ffff8116926201000082041691600160581b9091041687565b604080516001600160481b039889168152968816602088015264ffffffffff95861690870152928616606086015261ffff90911660808501529390931660a083015290911660c082015260e00161022e565b61024a6104f136600461296f565b61124c565b61024a611276565b61050661132a565b60405161022e9190612ab9565b610288610e3881565b61024a61052a36600461296f565b611439565b61028860065481565b600b602052816000526040600020818154811061055457600080fd5b60009182526020909120015464ffffffffff811692506001600160481b03600160281b820481169250600160701b8204169061ffff600160b81b8204811691600160c81b8104821691600160d81b9091041686565b6105b16114b2565b600180546001600160a01b0319166001600160a01b0392909216919091179055565b6105db6114b2565b600380546001600160a01b0319166001600160a01b0392909216919091179055565b6106056128be565b61060d6128be565b6106178282611520565b61061f611026565b336000908152600b6020526040812080549091036106775760405162461bcd60e51b815260206004820152601060248201526f195b5c1d1e481cdd185ad9481b1a5cdd60821b60448201526064015b60405180910390fd5b805485106106bc5760405162461bcd60e51b81526020600482015260126024820152711cdd185ad9525b99195e081a5b9d985b1a5960721b604482015260640161066e565b6106fc6040518060c00160405280600064ffffffffff16815260200160008152602001600081526020016000815260200160008152602001600081525090565b61072282878154811061071157610711612aeb565b9060005260206000200186836115a4565b61072b84611661565b6000808260a001516000141590506000806000905060008086606001518a60e00151106107b25784156107645786608001519550610798565b61076e8a88611671565b86606001518a60e001516107829190612b17565b9550866080015186111561079857866080015195505b6107a38a8888611698565b929650909450925090506107d3565b86604001518a6020018181516107c89190612b17565b905250602087015193505b6107ea8b8860200151896040015186868b8b61175b565b80158015906107f7575084155b15610806576108068a82611820565b8315610896576001546001600160a01b031663b4f56b263361082d876402540be400612b2a565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401600060405180830381600087803b15801561087357600080fd5b505af1158015610887573d6000803e3d6000fd5b505050506108968a88866118ef565b60208701518a518b906108aa908390612b17565b90525060025460405163a9db026960e01b815233600482015264ffffffffff8d1660248201526001600160a01b039091169063a9db026990604401600060405180830381600087803b1580156108ff57600080fd5b505af1158015610913573d6000803e3d6000fd5b50505050610921888d61198e565b61092b8a8a611b03565b505050505050505050505050565b600854600354604080516361bf897b60e11b815290516000936001600160481b0316926402540be400926001600160a01b039091169163c37f12f6916004808201926020929091908290030181865afa15801561099a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109be9190612b49565b6109c89190612b62565b600154604080516318160ddd60e01b815290516402540be400926001600160a01b0316916318160ddd9160048083019260209291908290030181865afa158015610a16573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a3a9190612b49565b610a449190612b62565b610a4e9190612b84565b610a589190612b84565b905090565b610a656128be565b610a6d6128be565b610a778282611520565b610a7f611026565b6001831015610ac45760405162461bcd60e51b81526020600482015260116024820152706e65775374616b656444617973206c6f7760781b604482015260640161066e565b610acd82611661565b610ad8828585611c6d565b6001546001600160a01b031663a8a778ae33610af9876402540be400612b2a565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401600060405180830381600087803b158015610b3f57600080fd5b505af1158015610b53573d6000803e3d6000fd5b50505050610b618282611b03565b50505050565b6000610a58611f3e565b610b796128be565b610b816128be565b610b8b8282611520565b6001600160a01b0385166000908152600b60205260408120549003610be55760405162461bcd60e51b815260206004820152601060248201526f195b5c1d1e481cdd185ad9481b1a5cdd60821b604482015260640161066e565b6001600160a01b0385166000908152600b60205260409020548410610c415760405162461bcd60e51b81526020600482015260126024820152711cdd185ad9525b99195e081a5b9d985b1a5960721b604482015260640161066e565b6001600160a01b0385166000908152600b60205260408120805486908110610c6b57610c6b612aeb565b906000526020600020019050610cb76040518060c00160405280600064ffffffffff16815260200160008152602001600081526020016000815260200160008152602001600081525090565b610cc28286836115a4565b80608001518160600151610cd69190612b84565b8460e001511015610d225760405162461bcd60e51b815260206004820152601660248201527514dd185ad9481b9bdd08199d5b1b1e481cd95c9d995960521b604482015260640161066e565b60a081015115610d6d5760405162461bcd60e51b815260206004820152601660248201527514dd185ad948185b1c9958591e481d5b9b1bd8dad95960521b604482015260640161066e565b610d7684611661565b610d808482611671565b6000806000610d9487858660800151611698565b93509350935050610db18a89866020015187604001518787611f5c565b8015610dc157610dc18782611820565b83518554602086015160408701516060880151608089015160a08a015164ffffffffff9096166001600160701b031990951694909417600160281b6001600160481b039485160217600160701b600160c81b031916600160701b939092169290920261ffff60b81b191617600160b81b61ffff928316021763ffffffff60c81b1916600160c81b9282169290920261ffff60d81b191691909117600160d81b9190921602178555610e728787611b03565b50505050505050505050565b60608183108015610e95575060095461ffff168211155b610ed15760405162461bcd60e51b815260206004820152600d60248201526c1c985b99d9481a5b9d985b1a59609a1b604482015260640161066e565b610edb8383612b17565b67ffffffffffffffff811115610ef357610ef3612b97565b604051908082528060200260200182016040528015610f1c578160200160208202803683370190505b509050826000805b610f3060486002612b2a565b6000848152600a6020526040902054600160901b810466ffffffffffffff1690911b600160481b820460481b71ffffffffffffffffff00000000000000000016176001600160481b03909116179050808483610f8b81612bad565b945081518110610f9d57610f9d612aeb565b602090810291909101015284610fb284612bad565b93508310610f24575050505b92915050565b6000600a610fd28385612b17565b6014600554610fe19190612b17565b610feb9190612b2a565b610ff59190612b62565b610fff9085612b2a565b61100a90600b612b2a565b949350505050565b61101a6114b2565b6110246000611ff9565b565b600062093a806007544261103a9190612b17565b101590506000600160009054906101000a90046001600160a01b03166001600160a01b03166351e238e36040518163ffffffff1660e01b81526004016020604051808303816000875af1158015611095573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110b99190612b49565b600160009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561110c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111309190612b49565b11905080801561114257506028600554105b801561114b5750815b15611169576005805461115d91612b84565b60055542600755611188565b8015801561117957506014600554115b15611188576014600555426007555b60055461119790618e30612b62565b6006555050565b6111a66128be565b6111ae6128be565b6111b88282611520565b821561122d578160e0015183111561121c5760405162461bcd60e51b815260206004820152602160248201527f6265666f72654461792063616e6e6f7420626520696e207468652066757475726044820152606560f81b606482015260840161066e565b61122882846000612049565b61123d565b61123d828360e001516000612049565b6112478282611b03565b505050565b6112546114b2565b600280546001600160a01b0319166001600160a01b0392909216919091179055565b600c5460ff16156112b55760405162461bcd60e51b81526020600482015260096024820152681a5b9a5d1a585d195960ba1b604482015260640161066e565b6112be33611ff9565b6112cc620186a06001612b2a565b6008805464ffffffffff92909216600160901b0264ffffffffff60901b199092169190911790556009805461ffff19166001179055426004556014600581905561131890618e30612b62565b600655600c805460ff19166001179055565b61133261290a565b60408051610120810182526008546001600160481b038082168352600160481b8204811660208085019190915264ffffffffff600160901b8404811685870152600160b81b9093048216606085015260095461ffff8116608086015262010000810490921660a0850152600160581b90910490911660c08301524260e083015260015483516318160ddd60e01b8152935192936101008501936402540be400936001600160a01b03909316926318160ddd92600480820193918290030181865afa158015611404573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114289190612b49565b6114329190612b62565b9052919050565b6114416114b2565b6001600160a01b0381166114a65760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b606482015260840161066e565b6114af81611ff9565b50565b6000546001600160a01b03163314806114d457506000546001600160a01b0316155b6110245760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161066e565b6008546001600160481b038082168452600160481b82048116602085015264ffffffffff600160901b830481166040860152600160b81b9092048116606085015260095461ffff8116608086015262010000810490911660a0850152600160581b90041660c0830152611591611f3e565b60e08301526115a08282612229565b5050565b825464ffffffffff8381169116146115fe5760405162461bcd60e51b815260206004820152601960248201527f7374616b654964506172616d206e6f7420696e207374616b6500000000000000604482015260640161066e565b915464ffffffffff811683526001600160481b03600160281b820481166020850152600160701b820416604084015261ffff600160b81b820481166060850152600160c81b820481166080850152600160d81b9091041660a09092019190915250565b6114af818260e001516001612049565b80604001518260a0018181516116879190612b17565b90525060e09091015160a090910152565b60008060008085608001518510156116df576116c38787606001518860800151888a60400151612271565b602088015191945092506116d8908490612b84565b935061172c565b604086015160608701516116fd91906116f88882612b84565b61237e565b925082866020015161170f9190612b84565b9350611729866060015187608001518860a00151876123e7565b91505b811561175257838211156117435750600092611752565b508061174f8185612b17565b93505b93509350935093565b8664ffffffffff16336001600160a01b03167f72d9c5a7ab13846e08d9c838f9e866a1bb4a66a2fd3ba3c9e7da3cf9e394dfd760b8876001600160481b0316901b6070896001600160481b0316901b60288b6001600160481b0316901b4264ffffffffff16171717846117cf5760006117d5565b600160581b5b6bffffffffffffffffffffffff1660488761ffff16901b886001600160481b0316171760405161180f929190918252602082015260400190565b60405180910390a350505050505050565b600061182d600283612b62565b905080156118c9576001546001600160a01b031663b4f56b2673c0c607cf29852476311b4c17328d18a2d02a845c61186a846402540be400612b2a565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401600060405180830381600087803b1580156118b057600080fd5b505af11580156118c4573d6000803e3d6000fd5b505050505b6118d38183612b17565b905080836060018181516118e79190612b84565b905250505050565b8160200151811115611247576000611910828460800151856000015161243e565b905060008360400151620186a083856119299190612b84565b6119339190612b2a565b61193d9190612b62565b905061194e6001600160281b612b17565b811115611967576119646001600160281b612b17565b90505b8460400151811115611987576040850181905283516119879082906125ce565b5050505050565b815460009061199f90600190612b17565b9050808214611acc578281815481106119ba576119ba612aeb565b906000526020600020018383815481106119d6576119d6612aeb565b6000918252602090912082549101805464ffffffffff90921664ffffffffff1983168117825583546001600160701b031990931617600160281b928390046001600160481b0390811690930217808255835468ffffffffffffffffff60701b198216600160701b918290049094160292831782558354600160701b600160c81b031990911661ffff60b81b1990931692909217600160b81b9283900461ffff90811690930217808255835461ffff60c81b198216600160c81b9182900485169091029081178355935463ffffffff60c81b1990911661ffff60d81b1990941693909317600160d81b938490049092169092021790555b82805480611adc57611adc612bc6565b600082815260209020810160001990810180546001600160e81b0319169055019055505050565b80518251141580611b1c57508060200151826020015114155b80611b2f57508060400151826040015114155b80611b4257508060600151826060015114155b15611bc5578151600880546020850151604086015160608701516001600160481b03908116600160b81b026001600160b81b0364ffffffffff909316600160901b029290921671ffffffffffffffffffffffffffffffffffff938216600160481b026001600160901b031990951691909616179290921716929092179190911790555b80608001518260800151141580611be457508060a001518260a0015114155b80611c0557508060c0015164ffffffffff168260c0015164ffffffffff1614155b156115a05760808201516009805460a085015160c086015164ffffffffff16600160581b0264ffffffffff60581b196001600160481b0390921662010000026affffffffffffffffffffff1990931661ffff9095169490941791909117169190911790555050565b6115b3811115611cb45760405162461bcd60e51b81526020600482015260126024820152710dccaeea6e8c2d6cac888c2f2e640d0d2ced60731b604482015260640161066e565b60008360c0018051611cc590612bdc565b64ffffffffff169081905260025460405163903acf5160e01b8152336004820152602481018390529192506001600160a01b03169063903acf51906044016020604051808303816000875af1158015611d22573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d469190612c00565b506000611d5484848461243e565b905060008560400151620186a08387611d6d9190612b84565b611d779190612b2a565b611d819190612b62565b905080600003611ddd5760405162461bcd60e51b815260206004820152602160248201527f6e65775374616b65645873206d757374206265203e3d206d696e2063645261746044820152606560f81b606482015260840161066e565b60008660e001516001611df09190612b84565b336000908152600b60205260409020909150611f0090858885858a6040805160c08101825264ffffffffff96871681526001600160481b03958616602080830191825295871692820192835261ffff9485166060830190815293851660808301908152600060a084018181528b54600181018d559b82529790209251929099018054915193519451995196518616600160d81b0261ffff60d81b19978716600160c81b029790971663ffffffff60c81b199a909616600160b81b0261ffff60b81b19958916600160701b0295909516600160701b600160c81b031994909816600160281b026001600160701b03199092169290981691909117171693909317929092179390931617919091179055565b611f0c84878488612627565b8187602001818151611f1e9190612b84565b905250865186908890611f32908390612b84565b90525050505050505050565b60006201518060045442611f529190612b17565b610a589190612b62565b604080514264ffffffffff9081166dffffffffffffffffff0000000000602889901b161768ffffffffffffffffff60701b607088901b16176001600160b81b031960b887901b161782526001600160481b03841660208301523392908816916001600160a01b038a16917fd824970a2cf19cc2b630c87ce5b00f67301cac3ac60513d027c7a39129f93b46910160405180910390a4505050505050565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b8183608001511061205957505050565b61207d60405180606001604052806000815260200160008152602001600081525090565b8351600154604080516318160ddd60e01b815290516402540be400926001600160a01b0316916318160ddd9160048083019260209291908290030181865afa1580156120cd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120f19190612b49565b6120fb9190612b62565b6121059190612b84565b815260808401516121178583836126ab565b6020850151156121425784602001518560a0018181516121379190612b84565b905250600060208601525b8361214c82612bad565b9150811015612165576121608583836126ab565b612142565b612174856080015182856126fc565b608085018190526020820151156119875760015460208301516001600160a01b039091169063b4f56b269073c0c607cf29852476311b4c17328d18a2d02a845c906121c4906402540be400612b2a565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401600060405180830381600087803b15801561220a57600080fd5b505af115801561221e573d6000803e3d6000fd5b505050505050505050565b815181526020808301519082015260408083015190820152606080830151908201526080808301519082015260a0808301519082015260c09182015164ffffffffff16910152565b6000808061227f8588612b84565b905060006002612290886001612b84565b61229a9190612b62565b9050605a8110156122a95750605a5b856000036122d45760006122be8a878b612775565b90506122ca8282612b2a565b9350505050612374565b8581101561231b5760006122e8828a612b84565b90506122f5868a8361237e565b9350600061230487838661237e565b90506123108186612b84565b955050505050612374565b61232685898461237e565b935085810361233757839250612371565b856123428286612b2a565b61234c9190612b62565b92506014600554111561237157612364848888610fc4565b61236e9084612b84565b92505b50505b9550959350505050565b6000825b828110156123df576000818152600a60205260409020546001600160481b03600160481b82048116916123b791889116612b2a565b6123c19190612b62565b6123cb9083612b84565b9150806123d781612bad565b915050612382565b509392505050565b600080600e6123f68688612b84565b6124009190612b84565b905080841161241357600091505061100a565b6102bc6124208286612b17565b61242a9085612b2a565b6124349190612b62565b9695505050505050565b600080600184111561246a57610e3884111561245c57610e38612467565b612467600185612b17565b90505b600061247e6305f5e1006308f0d180612b2a565b86111561249c576124976305f5e1006308f0d180612b2a565b61249e565b855b9050600654816124ae9190612b2a565b600a6124c26305f5e1006308f0d180612b2a565b6124cd906064612b2a565b6124d79190612b62565b6124e19084612b2a565b6124eb9190612b84565b9250600a6125016305f5e1006308f0d180612b2a565b61250c906064612b2a565b6125169190612b62565b6006546125239190612b2a565b61252d8488612b2a565b6125379190612b62565b60025460405163157a04bb60e21b815264ffffffffff87166004820152919450600a916001600160a01b03909116906355e812ec90602401602060405180830381865afa15801561258c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125b09190612b49565b6125ba9085612b2a565b6125c49190612b62565b6124349084612b84565b8064ffffffffff167f7c289df238c8a368f40a4e87d0c1164b73f1cee6b3759a3f7b8d261fae2f14c960288464ffffffffff16901b4264ffffffffff161760405161261b91815260200190565b60405180910390a25050565b60405164ffffffffff8086169133917f14872dc760f33532684e68e1b6d5fd3f71ba7b07dee76bdb2b084f28b74233ef9161269d9142166dffffffffffffffffff000000000060288a901b161768ffffffffffffffffff60701b607089901b161761ffff60b81b60b888901b1617815260200190565b60405180910390a350505050565b6126b683838361286c565b6040918201516000918252600a602052919020805460a0909301516001600160481b03908116600160481b026001600160901b0319909416921691909117919091179055565b337fb8d6eb541ded1720cc657b719f57abcb1fe4711cb7ead82751b135f5d94bc9448261272a576000612730565b600160481b5b69ffffffffffffffffffff1660388561ffff16901b60288761ffff16901b4264ffffffffff1617171760405161276891815260200190565b60405180910390a2505050565b600061277f6128be565b6127898582612229565b6127ad60405180606001604052806000815260200160008152602001600081525090565b8551600154604080516318160ddd60e01b815290516402540be400926001600160a01b0316916318160ddd9160048083019260209291908290030181865afa1580156127fd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128219190612b49565b61282b9190612b62565b6128359190612b84565b815261284282828661286c565b848260a0018181516128549190612b84565b90525060a0820151604082015161242a908790612b2a565b815163043763b39061288090612710612b2a565b61288a9190612b62565b6040830152606083015115611247578260600151826040018181516128af9190612b84565b90525060006060840152505050565b604051806101000160405280600081526020016000815260200160008152602001600081526020016000815260200160008152602001600064ffffffffff168152602001600081525090565b6040518061012001604052806009906020820280368337509192915050565b80356001600160a01b038116811461294057600080fd5b919050565b6000806040838503121561295857600080fd5b61296183612929565b946020939093013593505050565b60006020828403121561298157600080fd5b61298a82612929565b9392505050565b803564ffffffffff8116811461294057600080fd5b600080604083850312156129b957600080fd5b823591506129c960208401612991565b90509250929050565b600080604083850312156129e557600080fd5b50508035926020909101359150565b600080600060608486031215612a0957600080fd5b612a1284612929565b925060208401359150612a2760408501612991565b90509250925092565b6020808252825182820181905260009190848201906040850190845b81811015612a6857835183529284019291840191600101612a4c565b50909695505050505050565b600080600060608486031215612a8957600080fd5b505081359360208301359350604090920135919050565b600060208284031215612ab257600080fd5b5035919050565b6101208101818360005b6009811015612ae2578151835260209283019290910190600101612ac3565b50505092915050565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b81810381811115610fbe57610fbe612b01565b6000816000190483118215151615612b4457612b44612b01565b500290565b600060208284031215612b5b57600080fd5b5051919050565b600082612b7f57634e487b7160e01b600052601260045260246000fd5b500490565b80820180821115610fbe57610fbe612b01565b634e487b7160e01b600052604160045260246000fd5b600060018201612bbf57612bbf612b01565b5060010190565b634e487b7160e01b600052603160045260246000fd5b600064ffffffffff808316818103612bf657612bf6612b01565b6001019392505050565b600060208284031215612c1257600080fd5b8151801515811461298a57600080fdfea2646970667358221220c078c9a5fe317137d5ee5993a40f66525cb7c6f93bdca272ec42e0735d69332764736f6c63430008100033