Ape Curtis Testnet

Contract

0xc6f268Ddf4F9122CF47988Dbd46fA0B103B8770F

Overview

APE Balance

Ape Curtis LogoApe Curtis LogoApe Curtis Logo0 APE

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To

There are no matching entries

Please try again later

Latest 1 internal transaction

Parent Transaction Hash Block From To
129660302024-11-24 17:59:3728 days ago1732471177
0xc6f268Dd...103B8770F
0 APE

Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
World

Compiler Version
v0.8.20+commit.a1b79de6

Optimization Enabled:
Yes with 1000 runs

Other Settings:
paris EvmVersion

Contract Source Code (Solidity Standard Json-Input format)

File 1 of 28 : World.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import {UUPSUpgradeable} from "./ozUpgradeable/proxy/utils/UUPSUpgradeable.sol";
import {OwnableUpgradeable} from "./ozUpgradeable/access/OwnableUpgradeable.sol";

import {UnsafeMath, U256} from "@0xdoublesharp/unsafe-math/contracts/UnsafeMath.sol";

// TODO: Find alternate VRF provider
import {SamWitchVRFConsumerUpgradeable} from "./SamWitchVRFConsumerUpgradeable.sol";
import {ISamWitchVRF} from "./interfaces/ISamWitchVRF.sol";
import {IOracleRewardCB} from "./interfaces/IOracleRewardCB.sol";

import {WorldLibrary} from "./WorldLibrary.sol";

// solhint-disable-next-line no-global-import
import "./globals/all.sol";

contract World is SamWitchVRFConsumerUpgradeable, UUPSUpgradeable, OwnableUpgradeable {
  using UnsafeMath for U256;
  using UnsafeMath for uint;

  event RequestSent(uint requestId, uint32 numWords, uint lastRandomWordsUpdatedTime);
  event RequestFulfilled(uint requestId, uint randomWord);
  event AddActions(Action[] actions);
  event EditActions(Action[] actions);
  event AddActionChoices(uint16 actionId, uint16[] actionChoiceIds, ActionChoiceInput[] choices);
  event EditActionChoices(uint16 actionId, uint16[] actionChoiceIds, ActionChoiceInput[] choices);
  event RemoveActionChoices(uint16 actionId, uint16[] actionChoiceIds);

  error RandomWordsCannotBeUpdatedYet();
  error CanOnlyRequestAfterTheNextCheckpoint(uint currentTime, uint checkpoint);
  error RequestAlreadyFulfilled();
  error NoValidRandomWord();
  error CanOnlyRequestAfter1DayHasPassed();
  error ActionIdZeroNotAllowed();
  error MinCannotBeGreaterThanMax();
  error DynamicActionsCannotBeAdded();
  error ActionAlreadyExists(uint16 actionId);
  error ActionDoesNotExist();
  error ActionChoiceIdZeroNotAllowed();
  error DynamicActionsCannotBeSet();
  error LengthMismatch();
  error NoActionChoices();
  error ActionChoiceAlreadyExists();
  error ActionChoiceDoesNotExist();
  error NotAFactorOf3600();
  error NonCombatWithActionChoicesCannotHaveBothGuaranteedAndRandomRewards();
  error InvalidReward();
  error TooManyRewardsInPool();
  error CallbackGasLimitTooHigh();

  // Past request ids
  uint[] public requestIds; // Each one is a set of random words for 1 day
  mapping(uint requestId => uint randomWord) public randomWords;
  uint40 public lastRandomWordsUpdatedTime;
  uint40 private startTime;
  uint40 private weeklyRewardCheckpoint;
  bytes8 public thisWeeksRandomWordSegment; // Every 8 bits is a random segment for the day
  uint24 private callbackGasLimit;

  uint32 private constant NUM_WORDS = 1;

  uint32 public constant MIN_RANDOM_WORDS_UPDATE_TIME = 1 days;
  uint32 private constant MIN_DYNAMIC_ACTION_UPDATE_TIME = 1 days;

  uint32 public constant NUM_DAYS_RANDOM_WORDS_INITIALIZED = 3;

  mapping(uint actionId => ActionInfo actionInfo) public actions;
  uint16[] private lastAddedDynamicActions;
  uint private lastDynamicUpdatedTime;

  /// @custom:oz-renamed-from dailyRewards
  bytes32 dummy; // Not clean

  mapping(uint actionId => mapping(uint16 choiceId => ActionChoice actionChoice)) private actionChoices;
  mapping(uint actionId => CombatStats combatStats) private actionCombatStats;

  mapping(uint actionId => ActionRewards actionRewards) private actionRewards;

  IOracleRewardCB private quests;

  mapping(uint tier => Equipment[]) public dailyRewardPool;
  mapping(uint tier => Equipment[]) public weeklyRewardPool;

  IOracleRewardCB private wishingWell;

  /// @custom:oz-upgrades-unsafe-allow constructor
  constructor() {
    _disableInitializers();
  }

  function initialize(address _vrf) external initializer {
    __SamWitchVRFConsumerUpgradeable_init(ISamWitchVRF(_vrf));
    __UUPSUpgradeable_init();
    __Ownable_init();

    startTime = uint40(
      (block.timestamp / MIN_RANDOM_WORDS_UPDATE_TIME) *
        MIN_RANDOM_WORDS_UPDATE_TIME -
        (NUM_DAYS_RANDOM_WORDS_INITIALIZED + 1) *
        1 days
    ); // Floor to the nearest day 00:00 UTC
    lastRandomWordsUpdatedTime = uint40(startTime + NUM_DAYS_RANDOM_WORDS_INITIALIZED * 1 days);
    weeklyRewardCheckpoint = uint40((block.timestamp - 4 days) / 1 weeks) * 1 weeks + 4 days + 1 weeks;
    callbackGasLimit = 600_000;

    // Initialize a few days worth of random words so that we have enough data to fetch the first day
    for (U256 iter; iter.lt(NUM_DAYS_RANDOM_WORDS_INITIALIZED); iter = iter.inc()) {
      uint i = iter.asUint256();
      uint requestId = 200 + i;
      requestIds.push(requestId);
      emit RequestSent(requestId, NUM_WORDS, startTime + (i * 1 days) + 1 days);
      uint[] memory _randomWords = new uint[](1);
      _randomWords[0] = uint(
        blockhash(block.number - NUM_DAYS_RANDOM_WORDS_INITIALIZED + i) ^
          0x3632d8eba811d69784e6904a58de6e0ab55f32638189623b309895beaa6920c4
      );
      _fulfillRandomWords(requestId, _randomWords);
    }

    thisWeeksRandomWordSegment = bytes8(uint64(randomWords[0]));
  }

  function requestRandomWords() external returns (uint requestId) {
    // Last one has not been fulfilled yet
    if (requestIds.length != 0 && randomWords[requestIds[requestIds.length - 1]] == 0) {
      revert RandomWordsCannotBeUpdatedYet();
    }
    uint40 newLastRandomWordsUpdatedTime = lastRandomWordsUpdatedTime + MIN_RANDOM_WORDS_UPDATE_TIME;
    if (newLastRandomWordsUpdatedTime > block.timestamp) {
      revert CanOnlyRequestAfterTheNextCheckpoint(block.timestamp, newLastRandomWordsUpdatedTime);
    }

    requestId = uint256(samWitchVRF.requestRandomWords(NUM_WORDS, callbackGasLimit));
    requestIds.push(requestId);
    lastRandomWordsUpdatedTime = newLastRandomWordsUpdatedTime;
    emit RequestSent(requestId, NUM_WORDS, newLastRandomWordsUpdatedTime);
    return requestId;
  }

  function fulfillRandomWords(bytes32 _requestId, uint[] memory _randomWords) external onlySamWitchVRF {
    _fulfillRandomWords(uint(_requestId), _randomWords);
  }

  function getWeeklyReward(uint _tier, uint _playerId) public view returns (uint16 itemTokenId, uint24 amount) {
    uint day = 7;
    uint index = _getRewardIndex(_playerId, day, uint64(thisWeeksRandomWordSegment), weeklyRewardPool[_tier].length);
    Equipment storage equipment = weeklyRewardPool[_tier][index];
    return (equipment.itemTokenId, equipment.amount);
  }

  function getSpecificDailyReward(
    uint _tier,
    uint _playerId,
    uint _day,
    uint _randomWord
  ) public view returns (uint16 itemTokenId, uint24 amount) {
    uint index = _getRewardIndex(_playerId, _day, _randomWord, dailyRewardPool[_tier].length);
    Equipment storage equipment = dailyRewardPool[_tier][index];
    return (equipment.itemTokenId, equipment.amount);
  }

  function getDailyReward(uint _tier, uint _playerId) external view returns (uint itemTokenId, uint amount) {
    uint checkpoint = ((block.timestamp - 4 days) / 1 weeks) * 1 weeks + 4 days;
    uint day = ((block.timestamp / 1 days) * 1 days - checkpoint) / 1 days;
    return getSpecificDailyReward(_tier, _playerId, day, uint64(thisWeeksRandomWordSegment));
  }

  function getActiveDailyAndWeeklyRewards(
    uint _tier,
    uint _playerId
  ) external view returns (Equipment[8] memory rewards) {
    for (uint i; i < 7; ++i) {
      (rewards[i].itemTokenId, rewards[i].amount) = getSpecificDailyReward(
        _tier,
        _playerId,
        i,
        uint64(thisWeeksRandomWordSegment)
      );
    }
    (rewards[7].itemTokenId, rewards[7].amount) = getWeeklyReward(_tier, _playerId);
  }

  function _getRandomWordOffset(uint _timestamp) private view returns (int) {
    if (_timestamp < startTime) {
      return -1;
    }
    return int((_timestamp - startTime) / MIN_RANDOM_WORDS_UPDATE_TIME);
  }

  function _getRandomWord(uint _timestamp) private view returns (uint) {
    int offset = _getRandomWordOffset(_timestamp);
    if (offset < 0 || requestIds.length <= uint(offset)) {
      return 0;
    }
    return randomWords[requestIds[uint(offset)]];
  }

  function hasRandomWord(uint _timestamp) external view returns (bool) {
    return _getRandomWord(_timestamp) != 0;
  }

  function getRandomWord(uint _timestamp) public view returns (uint randomWord) {
    randomWord = _getRandomWord(_timestamp);
    if (randomWord == 0) {
      revert NoValidRandomWord();
    }
  }

  function getMultipleWords(uint _timestamp) public view returns (uint[4] memory words) {
    for (U256 iter; iter.lt(4); iter = iter.inc()) {
      uint i = iter.asUint256();
      words[i] = getRandomWord(_timestamp - (i * 1 days));
    }
  }

  function getSkill(uint _actionId) external view returns (Skill) {
    return actions[_actionId].skill;
  }

  function getActionRewards(uint _actionId) external view returns (ActionRewards memory) {
    return actionRewards[_actionId];
  }

  function getActionInfo(uint _actionId) external view returns (ActionInfo memory info) {
    return actions[_actionId];
  }

  function getXPPerHour(uint16 _actionId, uint16 _actionChoiceId) external view returns (uint24 xpPerHour) {
    return _actionChoiceId != 0 ? actionChoices[_actionId][_actionChoiceId].xpPerHour : actions[_actionId].xpPerHour;
  }

  function getNumSpawn(uint16 _actionId) external view returns (uint numSpawned) {
    return actions[_actionId].numSpawned;
  }

  function getCombatStats(uint16 _actionId) external view returns (CombatStats memory stats) {
    stats = actionCombatStats[_actionId];
  }

  function getActionChoice(uint16 _actionId, uint16 _choiceId) external view returns (ActionChoice memory choice) {
    ActionChoice storage actionChoice = actionChoices[_actionId][_choiceId];
    choice.skill = actionChoice.skill;
    choice.minXP = actionChoice.minXP;
    choice.skillDiff = actionChoice.skillDiff;
    choice.rate = actionChoice.rate;
    choice.xpPerHour = actionChoice.xpPerHour;
    choice.inputTokenId1 = actionChoice.inputTokenId1;
    choice.inputAmount1 = actionChoice.inputAmount1;
    choice.inputTokenId2 = actionChoice.inputTokenId2;
    choice.inputAmount2 = actionChoice.inputAmount2;
    choice.inputTokenId3 = actionChoice.inputTokenId3;
    choice.inputAmount3 = actionChoice.inputAmount3;
    choice.outputTokenId = actionChoice.outputTokenId;
    choice.outputAmount = actionChoice.outputAmount;
    choice.successPercent = actionChoice.successPercent;
    choice.handItemTokenIdRangeMin = actionChoice.handItemTokenIdRangeMin;
    choice.handItemTokenIdRangeMax = actionChoice.handItemTokenIdRangeMax;
    choice.packedData = actionChoice.packedData;
    // Only read second storage when needed
    if (
      (uint8(choice.packedData >> ACTION_CHOICE_USE_NEW_MIN_SKILL_SECOND_STORAGE_SLOT_BIT) & 1 == 1) ||
      (uint8(choice.packedData >> ACTION_CHOICE_USE_ALTERNATE_INPUTS_SECOND_STORAGE_SLOT) & 1 == 1)
    ) {
      choice.minSkill2 = actionChoice.minSkill2;
      choice.minXP2 = actionChoice.minXP2;
      choice.minSkill3 = actionChoice.minSkill3;
      choice.minXP3 = actionChoice.minXP3;

      choice.newInputAmount1 = actionChoice.newInputAmount1;
      choice.newInputAmount2 = actionChoice.newInputAmount2;
      choice.newInputAmount3 = actionChoice.newInputAmount3;
    }
  }

  function getActionSuccessPercentAndMinXP(
    uint16 _actionId
  ) external view returns (uint8 successPercent, uint32 minXP) {
    return (actions[_actionId].successPercent, actions[_actionId].minXP);
  }

  function getRewardsHelper(
    uint16 _actionId
  ) external view returns (ActionRewards memory, Skill skill, uint numSpanwed, uint8 worldLocation) {
    return (
      actionRewards[_actionId],
      actions[_actionId].skill,
      actions[_actionId].numSpawned,
      actions[_actionId].worldLocation
    );
  }

  function getRandomBytes(
    uint _numTickets,
    uint _startTimestamp,
    uint _endTimestamp,
    uint _playerId
  ) external view returns (bytes memory b) {
    if (_numTickets <= 16) {
      // 32 bytes
      bytes32 word = bytes32(getRandomWord(_endTimestamp));
      b = abi.encodePacked(_getRandomComponent(word, _startTimestamp, _endTimestamp, _playerId));
    } else if (_numTickets <= MAX_UNIQUE_TICKETS_) {
      // 4 * 32 bytes
      uint[4] memory multipleWords = getMultipleWords(_endTimestamp);
      for (U256 iter; iter.lt(4); iter = iter.inc()) {
        uint i = iter.asUint256();
        multipleWords[i] = uint(
          _getRandomComponent(bytes32(multipleWords[i]), _startTimestamp, _endTimestamp, _playerId)
        );
        // XOR all the words with the first fresh random number to give more randomness to the existing random words
        if (i != 0) {
          multipleWords[i] = uint(keccak256(abi.encodePacked(multipleWords[i] ^ multipleWords[0])));
        }
      }
      b = abi.encodePacked(multipleWords);
    } else {
      assert(false);
    }
  }

  function _addAction(Action calldata _action) private {
    if (_action.info.isDynamic) {
      revert DynamicActionsCannotBeAdded();
    }
    if (actions[_action.actionId].skill != Skill.NONE) {
      revert ActionAlreadyExists(_action.actionId);
    }
    _setAction(_action);
  }

  function _getRewardIndex(uint _playerId, uint _day, uint _randomWord, uint _length) private pure returns (uint) {
    return uint(keccak256(abi.encodePacked(_randomWord, _playerId)) >> (_day * 8)) % _length;
  }

  function _setAction(Action calldata _action) private {
    if (_action.actionId == 0) {
      revert ActionIdZeroNotAllowed();
    }
    if (_action.info.handItemTokenIdRangeMin > _action.info.handItemTokenIdRangeMax) {
      revert MinCannotBeGreaterThanMax();
    }

    if (_action.info.numSpawned != 0) {
      // Combat
      if ((3600 * SPAWN_MUL) % _action.info.numSpawned != 0) {
        revert NotAFactorOf3600();
      }
    } else if (_action.guaranteedRewards.length != 0) {
      // Non-combat guaranteed rewards. Only care about the first one as it's used for correctly taking into account partial loots.
      if ((3600 * GUAR_MUL) % _action.guaranteedRewards[0].rate != 0) {
        revert NotAFactorOf3600();
      }
    }

    actions[_action.actionId] = _action.info;

    // Set the rewards
    ActionRewards storage actionReward = actionRewards[_action.actionId];
    delete actionRewards[_action.actionId];
    WorldLibrary.setActionGuaranteedRewards(_action.guaranteedRewards, actionReward);
    WorldLibrary.setActionRandomRewards(_action.randomRewards, actionReward);

    if (_action.info.skill == Skill.COMBAT) {
      actionCombatStats[_action.actionId] = _action.combatStats;
    } else {
      bool actionHasGuaranteedRewards = _action.guaranteedRewards.length != 0;
      bool actionHasRandomRewards = _action.randomRewards.length != 0;
      if (actionHasGuaranteedRewards && actionHasRandomRewards && _action.info.actionChoiceRequired) {
        revert NonCombatWithActionChoicesCannotHaveBothGuaranteedAndRandomRewards();
      }
    }
  }

  function _addActionChoice(
    uint16 _actionId,
    uint16 _actionChoiceId,
    ActionChoiceInput calldata _actionChoiceInput
  ) private view {
    if (_actionChoiceId == 0) {
      revert ActionChoiceIdZeroNotAllowed();
    }
    if (actionChoices[_actionId][_actionChoiceId].skill != Skill.NONE) {
      revert ActionChoiceAlreadyExists();
    }
    WorldLibrary.checkActionChoice(_actionChoiceInput);
  }

  function _editActionChoice(
    uint16 _actionId,
    uint16 _actionChoiceId,
    ActionChoiceInput calldata _actionChoiceInput
  ) private view {
    if (actionChoices[_actionId][_actionChoiceId].skill == Skill.NONE) {
      revert ActionChoiceDoesNotExist();
    }

    WorldLibrary.checkActionChoice(_actionChoiceInput);
  }

  function _getRandomComponent(
    bytes32 _word,
    uint _startTimestamp,
    uint _endTimestamp,
    uint _playerId
  ) private pure returns (bytes32) {
    return keccak256(abi.encodePacked(_word, _startTimestamp, _endTimestamp, _playerId));
  }

  function _packActionChoice(
    ActionChoiceInput calldata _actionChoiceInput
  ) private pure returns (ActionChoice memory actionChoice) {
    bytes1 packedData = bytes1(uint8(_actionChoiceInput.isFullModeOnly ? 1 << IS_FULL_MODE_BIT : 0));
    if (_actionChoiceInput.minSkills.length > 1) {
      packedData |= bytes1(uint8(1)) << ACTION_CHOICE_USE_NEW_MIN_SKILL_SECOND_STORAGE_SLOT_BIT;
    }

    bool anyInputExceedsStandardAmount = (_actionChoiceInput.inputAmounts.length > 0 &&
      _actionChoiceInput.inputAmounts[0] > 255) ||
      (_actionChoiceInput.inputAmounts.length > 1 && _actionChoiceInput.inputAmounts[1] > 255) ||
      (_actionChoiceInput.inputAmounts.length > 2 && _actionChoiceInput.inputAmounts[2] > 255);

    if (anyInputExceedsStandardAmount) {
      packedData |= bytes1(uint8(1)) << ACTION_CHOICE_USE_ALTERNATE_INPUTS_SECOND_STORAGE_SLOT;
    }

    actionChoice = ActionChoice({
      skill: _actionChoiceInput.skill,
      minXP: _actionChoiceInput.minXPs.length != 0 ? _actionChoiceInput.minXPs[0] : 0,
      skillDiff: _actionChoiceInput.skillDiff,
      rate: _actionChoiceInput.rate,
      xpPerHour: _actionChoiceInput.xpPerHour,
      inputTokenId1: _actionChoiceInput.inputTokenIds.length > 0 ? _actionChoiceInput.inputTokenIds[0] : NONE,
      inputAmount1: _actionChoiceInput.inputAmounts.length > 0 && !anyInputExceedsStandardAmount
        ? uint8(_actionChoiceInput.inputAmounts[0])
        : 0,
      inputTokenId2: _actionChoiceInput.inputTokenIds.length > 1 ? _actionChoiceInput.inputTokenIds[1] : NONE,
      inputAmount2: _actionChoiceInput.inputAmounts.length > 1 && !anyInputExceedsStandardAmount
        ? uint8(_actionChoiceInput.inputAmounts[1])
        : 0,
      inputTokenId3: _actionChoiceInput.inputTokenIds.length > 2 ? _actionChoiceInput.inputTokenIds[2] : NONE,
      inputAmount3: _actionChoiceInput.inputAmounts.length > 2 && !anyInputExceedsStandardAmount
        ? uint8(_actionChoiceInput.inputAmounts[2])
        : 0,
      outputTokenId: _actionChoiceInput.outputTokenId,
      outputAmount: _actionChoiceInput.outputAmount,
      successPercent: _actionChoiceInput.successPercent,
      handItemTokenIdRangeMin: _actionChoiceInput.handItemTokenIdRangeMin,
      handItemTokenIdRangeMax: _actionChoiceInput.handItemTokenIdRangeMax,
      packedData: packedData,
      reserved: bytes1(uint8(0)),
      // Second storage slot
      minSkill2: _actionChoiceInput.minSkills.length > 1 ? _actionChoiceInput.minSkills[1] : Skill.NONE,
      minXP2: _actionChoiceInput.minXPs.length > 1 ? _actionChoiceInput.minXPs[1] : 0,
      minSkill3: _actionChoiceInput.minSkills.length > 2 ? _actionChoiceInput.minSkills[2] : Skill.NONE,
      minXP3: _actionChoiceInput.minXPs.length > 2 ? _actionChoiceInput.minXPs[2] : 0,
      newInputAmount1: _actionChoiceInput.inputAmounts.length > 0 && anyInputExceedsStandardAmount
        ? _actionChoiceInput.inputAmounts[0]
        : 0,
      newInputAmount2: _actionChoiceInput.inputAmounts.length > 1 && anyInputExceedsStandardAmount
        ? _actionChoiceInput.inputAmounts[1]
        : 0,
      newInputAmount3: _actionChoiceInput.inputAmounts.length > 2 && anyInputExceedsStandardAmount
        ? _actionChoiceInput.inputAmounts[2]
        : 0
    });
  }

  function _fulfillRandomWords(uint _requestId, uint[] memory _randomWords) internal {
    if (randomWords[_requestId] != 0) {
      revert RequestAlreadyFulfilled();
    }

    if (_randomWords.length != NUM_WORDS) {
      revert LengthMismatch();
    }

    uint randomWord = _randomWords[0];
    if (randomWord == 0) {
      // Not sure if 0 can be selected, but in case use previous block hash as pseudo random number
      randomWord = uint(blockhash(block.number - 1));
    }

    randomWords[_requestId] = randomWord;
    if (address(quests) != address(0)) {
      quests.newOracleRandomWords(randomWord);
    }
    if (address(wishingWell) != address(0)) {
      wishingWell.newOracleRandomWords(randomWord);
    }
    emit RequestFulfilled(_requestId, randomWord);

    // Are we at the threshold for a new week
    if (weeklyRewardCheckpoint <= ((block.timestamp) / 1 days) * 1 days) {
      // Issue new daily rewards for each tier based on the new random words
      thisWeeksRandomWordSegment = bytes8(uint64(randomWord));

      weeklyRewardCheckpoint = uint40((block.timestamp - 4 days) / 1 weeks) * 1 weeks + 4 days + 1 weeks;
    }
  }

  function addActions(Action[] calldata _actions) external onlyOwner {
    U256 iter = _actions.length.asU256();
    while (iter.neq(0)) {
      iter = iter.dec();
      uint16 i = iter.asUint16();
      _addAction(_actions[i]);
    }
    emit AddActions(_actions);
  }

  function editActions(Action[] calldata _actions) external onlyOwner {
    for (uint i = 0; i < _actions.length; ++i) {
      if (actions[_actions[i].actionId].skill == Skill.NONE) {
        revert ActionDoesNotExist();
      }
      _setAction(_actions[i]);
    }
    emit EditActions(_actions);
  }

  function addActionChoices(
    uint16 _actionId,
    uint16[] calldata _actionChoiceIds,
    ActionChoiceInput[] calldata _actionChoices
  ) public onlyOwner {
    emit AddActionChoices(_actionId, _actionChoiceIds, _actionChoices);

    U256 actionChoiceLength = _actionChoices.length.asU256();
    if (actionChoiceLength.neq(_actionChoiceIds.length)) {
      revert LengthMismatch();
    }

    if (_actionChoiceIds.length == 0) {
      revert NoActionChoices();
    }

    for (U256 iter; iter < actionChoiceLength; iter = iter.inc()) {
      uint16 i = iter.asUint16();
      _addActionChoice(_actionId, _actionChoiceIds[i], _actionChoices[i]);
      // TODO: Could set the first storage slot only in cases where appropriate (same as editing)
      actionChoices[_actionId][_actionChoiceIds[i]] = _packActionChoice(_actionChoices[i]);
    }
  }

  // actionId of 0 means it is not tied to a specific action (combat)
  function addBulkActionChoices(
    uint16[] calldata _actionIds,
    uint16[][] calldata _actionChoiceIds,
    ActionChoiceInput[][] calldata _actionChoices
  ) external onlyOwner {
    if (_actionIds.length != _actionChoices.length) {
      revert LengthMismatch();
    }
    if (_actionIds.length == 0) {
      revert NoActionChoices();
    }

    U256 actionIdsLength = _actionIds.length.asU256();
    for (U256 iter; iter < actionIdsLength; iter = iter.inc()) {
      uint16 i = iter.asUint16();
      uint16 actionId = _actionIds[i];
      addActionChoices(actionId, _actionChoiceIds[i], _actionChoices[i]);
    }
  }

  function editActionChoices(
    uint16 _actionId,
    uint16[] calldata _actionChoiceIds,
    ActionChoiceInput[] calldata _actionChoices
  ) external onlyOwner {
    if (_actionChoiceIds.length == 0) {
      revert NoActionChoices();
    }
    if (_actionChoiceIds.length != _actionChoices.length) {
      revert LengthMismatch();
    }

    U256 actionIdsLength = _actionChoiceIds.length.asU256();
    for (U256 iter; iter < actionIdsLength; iter = iter.inc()) {
      uint16 i = iter.asUint16();
      _editActionChoice(_actionId, _actionChoiceIds[i], _actionChoices[i]);
      actionChoices[_actionId][_actionChoiceIds[i]] = _packActionChoice(_actionChoices[i]);
    }

    emit EditActionChoices(_actionId, _actionChoiceIds, _actionChoices);
  }

  function removeActionChoices(uint16 _actionId, uint16[] calldata _actionChoiceIds) external onlyOwner {
    if (_actionChoiceIds.length == 0) {
      revert NoActionChoices();
    }

    U256 length = _actionChoiceIds.length.asU256();
    for (U256 iter; iter < length; iter = iter.inc()) {
      uint16 i = iter.asUint16();
      delete actionChoices[_actionId][_actionChoiceIds[i]];
    }
    emit RemoveActionChoices(_actionId, _actionChoiceIds);
  }

  function setQuests(IOracleRewardCB _quests) external onlyOwner {
    quests = _quests;
  }

  function setWishingWell(IOracleRewardCB _wishingWell) external onlyOwner {
    wishingWell = _wishingWell;
  }

  function setDailyRewardPool(uint _tier, Equipment[] calldata _dailyRewards) external onlyOwner {
    if (_dailyRewards.length > 255) {
      revert TooManyRewardsInPool();
    }
    delete dailyRewardPool[_tier];

    for (uint i = 0; i < _dailyRewards.length; ++i) {
      // Amount should be divisible by 10 to allow percentage increases to be applied (like clan bonuses)
      if (_dailyRewards[i].itemTokenId == 0 || _dailyRewards[i].amount == 0 || _dailyRewards[i].amount % 10 != 0) {
        revert InvalidReward();
      }
      dailyRewardPool[_tier].push(_dailyRewards[i]);
    }
  }

  function setWeeklyRewardPool(uint _tier, Equipment[] calldata _weeklyRewards) external onlyOwner {
    if (_weeklyRewards.length > 255) {
      revert TooManyRewardsInPool();
    }

    delete weeklyRewardPool[_tier];

    for (uint i = 0; i < _weeklyRewards.length; ++i) {
      if (_weeklyRewards[i].itemTokenId == NONE || _weeklyRewards[i].amount == 0) {
        revert InvalidReward();
      }
      weeklyRewardPool[_tier].push(_weeklyRewards[i]);
    }
  }

  function setCallbackGasLimit(uint _gasLimit) external onlyOwner {
    if (_gasLimit > 3_000_000) {
      revert CallbackGasLimitTooHigh();
    }
    callbackGasLimit = uint24(_gasLimit);
  }

  function setVRF(address _vrf) external onlyOwner {
    samWitchVRF = ISamWitchVRF(_vrf);
  }

  // solhint-disable-next-line no-empty-blocks
  function _authorizeUpgrade(address newImplementation) internal override onlyOwner {}
}

File 2 of 28 : I256.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

import {UnsafeMath} from '../UnsafeMath.sol';

using UnsafeMath for int256;

type I256 is int256;

using {
    add as +,
    sub as -,
    mul as *,
    div as /,
    mod as %,
    neq as !=,
    eq as ==,
    lt as <,
    lte as <=,
    gt as >,
    gte as >=,
    and as &,
    or as |,
    xor as ^,
    not as ~
} for I256 global;

function add(I256 _i256, I256 _addend) pure returns (I256) {
    return I256.wrap(I256.unwrap(_i256).add(I256.unwrap(_addend)));
}

function sub(I256 _i256, I256 _subtrahend) pure returns (I256) {
    return I256.wrap(I256.unwrap(_i256).sub(I256.unwrap(_subtrahend)));
}

function mul(I256 _i256, I256 _multiplier) pure returns (I256) {
    return I256.wrap(I256.unwrap(_i256).mul(I256.unwrap(_multiplier)));
}

function div(I256 _i256, I256 _divisor) pure returns (I256) {
    return I256.wrap(I256.unwrap(_i256).div(I256.unwrap(_divisor)));
}

function mod(I256 _i256, I256 _divisor) pure returns (I256) {
    return I256.wrap(I256.unwrap(_i256).mod(I256.unwrap(_divisor)));
}

function and(I256 _i256, I256 _mask) pure returns (I256) {
    return I256.wrap(I256.unwrap(_i256) & I256.unwrap(_mask));
}

function or(I256 _i256, I256 _mask) pure returns (I256) {
    return I256.wrap(I256.unwrap(_i256) | I256.unwrap(_mask));
}

function xor(I256 _i256, I256 _mask) pure returns (I256) {
    return I256.wrap(I256.unwrap(_i256) ^ I256.unwrap(_mask));
}

function not(I256 _i256) pure returns (I256) {
    return I256.wrap(~I256.unwrap(_i256));
}

function neq(I256 _i256, I256 _bounds) pure returns (bool) {
    return I256.unwrap(_i256) != I256.unwrap(_bounds);
}

function eq(I256 _i256, I256 _bounds) pure returns (bool) {
    return I256.unwrap(_i256) == I256.unwrap(_bounds);
}

function lt(I256 _i256, I256 _bounds) pure returns (bool) {
    return I256.unwrap(_i256) < I256.unwrap(_bounds);
}

function lte(I256 _i256, I256 _bounds) pure returns (bool) {
    return I256.unwrap(_i256) <= I256.unwrap(_bounds);
}

function gt(I256 _i256, I256 _bounds) pure returns (bool) {
    return I256.unwrap(_i256) > I256.unwrap(_bounds);
}

function gte(I256 _i256, I256 _bounds) pure returns (bool) {
    return I256.unwrap(_i256) >= I256.unwrap(_bounds);
}

File 3 of 28 : U256.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

import {UnsafeMath} from '../UnsafeMath.sol';

using UnsafeMath for uint256;

type U256 is uint256;

using {
    add as +,
    sub as -,
    mul as *,
    div as /,
    mod as %,
    neq as !=,
    eq as ==,
    lt as <,
    lte as <=,
    gt as >,
    gte as >=,
    and as &,
    or as |,
    xor as ^,
    not as ~
} for U256 global;

function add(U256 _u256, U256 _addend) pure returns (U256) {
    return U256.wrap(U256.unwrap(_u256).add(U256.unwrap(_addend)));
}

function sub(U256 _u256, U256 _subtrahend) pure returns (U256) {
    return U256.wrap(U256.unwrap(_u256).sub(U256.unwrap(_subtrahend)));
}

function mul(U256 _u256, U256 _multiplier) pure returns (U256) {
    return U256.wrap(U256.unwrap(_u256).mul(U256.unwrap(_multiplier)));
}

function div(U256 _u256, U256 _divisor) pure returns (U256) {
    return U256.wrap(U256.unwrap(_u256).div(U256.unwrap(_divisor)));
}

function mod(U256 _u256, U256 _divisor) pure returns (U256) {
    return U256.wrap(U256.unwrap(_u256).mod(U256.unwrap(_divisor)));
}

function and(U256 _u256, U256 _mask) pure returns (U256) {
    return U256.wrap(U256.unwrap(_u256) & U256.unwrap(_mask));
}

function or(U256 _u256, U256 _mask) pure returns (U256) {
    return U256.wrap(U256.unwrap(_u256) | U256.unwrap(_mask));
}

function xor(U256 _u256, U256 _mask) pure returns (U256) {
    return U256.wrap(U256.unwrap(_u256) ^ U256.unwrap(_mask));
}

function not(U256 _u256) pure returns (U256) {
    return U256.wrap(~U256.unwrap(_u256));
}

function neq(U256 _u256, U256 _bounds) pure returns (bool) {
    return U256.unwrap(_u256) != U256.unwrap(_bounds);
}

function eq(U256 _u256, U256 _bounds) pure returns (bool) {
    return U256.unwrap(_u256) == U256.unwrap(_bounds);
}

function lt(U256 _u256, U256 _bounds) pure returns (bool) {
    return U256.unwrap(_u256) < U256.unwrap(_bounds);
}

function lte(U256 _u256, U256 _bounds) pure returns (bool) {
    return U256.unwrap(_u256) <= U256.unwrap(_bounds);
}

function gt(U256 _u256, U256 _bounds) pure returns (bool) {
    return U256.unwrap(_u256) > U256.unwrap(_bounds);
}

function gte(U256 _u256, U256 _bounds) pure returns (bool) {
    return U256.unwrap(_u256) >= U256.unwrap(_bounds);
}

File 4 of 28 : UnsafeMath.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// solhint-disable func-name-mixedcase

import {I256} from './types/I256.sol';
import {U256} from './types/U256.sol';

library UnsafeMath {
    /*********************
     * uint256 ->
     *********************/

    /// @dev Returns the addition of two unsigned integers
    /// @param _uint256 The first unsigned integer
    /// @param _addend The second unsigned integer
    /// @return The addition of the two unsigned integers
    function add(uint256 _uint256, uint256 _addend) internal pure returns (uint256) {
        unchecked {
            return _uint256 + _addend;
        }
    }

    /// @dev Returns the subtraction of two unsigned integers
    /// @param _uint256 The first unsigned integer
    /// @param _subtrahend The second unsigned integer
    /// @return The subtraction of the two unsigned integers
    function sub(uint256 _uint256, uint256 _subtrahend) internal pure returns (uint256) {
        unchecked {
            return _uint256 - _subtrahend;
        }
    }

    /// @dev Increments an unsigned integer by one
    /// @param _uint256 The unsigned integer
    /// @return The incremented unsigned integer
    function inc(uint256 _uint256) internal pure returns (uint256) {
        unchecked {
            return ++_uint256;
        }
    }

    /// @dev Decrements an unsigned integer by one
    /// @param _uint256 The unsigned integer
    /// @return The decremented unsigned integer
    function dec(uint256 _uint256) internal pure returns (uint256) {
        unchecked {
            return --_uint256;
        }
    }

    /// @dev Returns the multiplication of two unsigned integers
    /// @param _uint256 The first unsigned integer
    /// @param _multiplier The second unsigned integer
    /// @return The multiplication of the two unsigned integers
    function mul(uint256 _uint256, uint256 _multiplier) internal pure returns (uint256) {
        unchecked {
            return _uint256 * _multiplier;
        }
    }

    /// @dev Returns the exponentiation of two unsigned integers
    /// @param _uint256 The first unsigned integer
    /// @param _exponent The second unsigned integer
    /// @return The exponentiation of the two unsigned integers
    function exp(uint256 _uint256, uint256 _exponent) internal pure returns (uint256) {
        uint256 result;
        // solhint-disable-next-line no-inline-assembly
        assembly {
            result := exp(_uint256, _exponent)
        }
        return result;
    }

    /// @dev Returns the division of two unsigned integers
    /// @param _uint256 The first unsigned integer
    /// @param _divisor The second unsigned integer
    /// @return The division of the two unsigned integers
    function div(uint256 _uint256, uint256 _divisor) internal pure returns (uint256) {
        uint256 result;
        // solhint-disable-next-line no-inline-assembly
        assembly {
            result := div(_uint256, _divisor)
        }
        return result;
    }

    /// @dev Returns the remainder of the division of two unsigned integers
    /// @param _uint256 The first unsigned integer
    /// @param _divisor The second unsigned integer
    /// @return The remainder of the division of the two unsigned integers
    function mod(uint256 _uint256, uint256 _divisor) internal pure returns (uint256) {
        uint256 result;
        // solhint-disable-next-line no-inline-assembly
        assembly {
            result := mod(_uint256, _divisor)
        }
        return result;
    }

    /*********************
     * int256 ->
     *********************/

    /// @dev Returns the addition of two signed integers
    /// @param _int256 The first signed integer
    /// @param _addend The second signed integer
    /// @return The addition of the two signed integers
    function add(int256 _int256, int256 _addend) internal pure returns (int256) {
        unchecked {
            return _int256 + _addend;
        }
    }

    /// @dev Returns the subtraction of two signed integers
    /// @param _int256 The first signed integer
    /// @param _subtrahend The second signed integer
    /// @return The subtraction of the two signed integers
    function sub(int256 _int256, int256 _subtrahend) internal pure returns (int256) {
        unchecked {
            return _int256 - _subtrahend;
        }
    }

    /// @dev Increments a signed integer by one
    /// @param _int256 The signed integer
    /// @return The incremented signed integer
    function inc(int256 _int256) internal pure returns (int256) {
        unchecked {
            return ++_int256;
        }
    }

    /// @dev Decrements a signed integer by one
    /// @param _int256 The signed integer
    /// @return The decremented signed integer
    function dec(int256 _int256) internal pure returns (int256) {
        unchecked {
            return --_int256;
        }
    }

    /// @dev Returns the multiplication of two signed integers
    /// @param _int256 The first signed integer
    /// @param _multiplier The second signed integer
    /// @return The multiplication of the two signed integers
    function mul(int256 _int256, int256 _multiplier) internal pure returns (int256) {
        unchecked {
            return _int256 * _multiplier;
        }
    }

    /// @dev Returns the division of two signed integers
    /// @param _int256 The first signed integer
    /// @param _divisor The second signed integer
    /// @return The division of the two signed integers
    function div(int256 _int256, int256 _divisor) internal pure returns (int256) {
        int256 result;
        // solhint-disable-next-line no-inline-assembly
        assembly {
            result := sdiv(_int256, _divisor)
        }
        return result;
    }

    /// @dev Returns the remainder of the division of two signed integers
    /// @param _int256 The first signed integer
    /// @param _divisor The second signed integer
    /// @return The remainder of the division of the two signed integers
    function mod(int256 _int256, int256 _divisor) internal pure returns (int256) {
        int256 result;
        // solhint-disable-next-line no-inline-assembly
        assembly {
            result := smod(_int256, _divisor)
        }
        return result;
    }

    /*********************
     * I256 ->
     *********************/

    /// @dev Wraps an int256 into an I256
    /// @param _i256 The int256 to wrap
    /// @return i256 The wrapped I256
    function asI256(int256 _i256) internal pure returns (I256 i256) {
        return I256.wrap(_i256);
    }

    /// @dev Wraps a uint256 into an I256
    /// @param _i256 The uint256 to wrap
    /// @return i256 The wrapped I256
    function asI256(uint256 _i256) internal pure returns (I256 i256) {
        return I256.wrap(int256(_i256));
    }

    /// @dev Converts an I256 to a signed int256
    /// @param _i256 The I256 to convert
    /// @return signed The signed int256
    function asInt256(I256 _i256) internal pure returns (int256 signed) {
        return I256.unwrap(_i256);
    }

    /// @dev Converts an I256 to a signed int248
    /// @param _i256 The I256 to convert
    /// @return signed The signed int248
    function asInt248(I256 _i256) internal pure returns (int248 signed) {
        return int248(I256.unwrap(_i256));
    }

    /// @dev Converts an I256 to a signed int240
    /// @param _i256 The I256 to convert
    /// @return signed The signed int240
    function asInt240(I256 _i256) internal pure returns (int240 signed) {
        return int240(I256.unwrap(_i256));
    }

    /// @dev Converts an I256 to a signed int232
    /// @param _i256 The I256 to convert
    /// @return signed The signed int232
    function asInt232(I256 _i256) internal pure returns (int232 signed) {
        return int232(I256.unwrap(_i256));
    }

    /// @dev Converts an I256 to a signed int224
    /// @param _i256 The I256 to convert
    /// @return signed The signed int224
    function asInt224(I256 _i256) internal pure returns (int224 signed) {
        return int224(I256.unwrap(_i256));
    }

    /// @dev Converts an I256 to a signed int216
    /// @param _i256 The I256 to convert
    /// @return signed The signed int216
    function asInt216(I256 _i256) internal pure returns (int216 signed) {
        return int216(I256.unwrap(_i256));
    }

    /// @dev Converts an I256 to a signed int208
    /// @param _i256 The I256 to convert
    /// @return signed The signed int208
    function asInt208(I256 _i256) internal pure returns (int208 signed) {
        return int208(I256.unwrap(_i256));
    }

    /// @dev Converts an I256 to a signed int200
    /// @param _i256 The I256 to convert
    /// @return signed The signed int200
    function asInt200(I256 _i256) internal pure returns (int200 signed) {
        return int200(I256.unwrap(_i256));
    }

    /// @dev Converts an I256 to a signed int192
    /// @param _i256 The I256 to convert
    /// @return signed The signed int192
    function asInt192(I256 _i256) internal pure returns (int192 signed) {
        return int192(I256.unwrap(_i256));
    }

    /// @dev Converts an I256 to a signed int184
    /// @param _i256 The I256 to convert
    /// @return signed The signed int184
    function asInt184(I256 _i256) internal pure returns (int184 signed) {
        return int184(I256.unwrap(_i256));
    }

    /// @dev Converts an I256 to a signed int176
    /// @param _i256 The I256 to convert
    /// @return signed The signed int176
    function asInt176(I256 _i256) internal pure returns (int176 signed) {
        return int176(I256.unwrap(_i256));
    }

    /// @dev Converts an I256 to a signed int168
    /// @param _i256 The I256 to convert
    /// @return signed The signed int168
    function asInt168(I256 _i256) internal pure returns (int168 signed) {
        return int168(I256.unwrap(_i256));
    }

    /// @dev Converts an I256 to a signed int160
    /// @param _i256 The I256 to convert
    /// @return signed The signed int160
    function asInt160(I256 _i256) internal pure returns (int160 signed) {
        return int160(I256.unwrap(_i256));
    }

    /// @dev Converts an I256 to a signed int152
    /// @param _i256 The I256 to convert
    /// @return signed The signed int152
    function asInt152(I256 _i256) internal pure returns (int152 signed) {
        return int152(I256.unwrap(_i256));
    }

    /// @dev Converts an I256 to a signed int144
    /// @param _i256 The I256 to convert
    /// @return signed The signed int144
    function asInt144(I256 _i256) internal pure returns (int144 signed) {
        return int144(I256.unwrap(_i256));
    }

    /// @dev Converts an I256 to a signed int136
    /// @param _i256 The I256 to convert
    /// @return signed The signed int136
    function asInt136(I256 _i256) internal pure returns (int136 signed) {
        return int136(I256.unwrap(_i256));
    }

    /// @dev Converts an I256 to a signed int128
    /// @param _i256 The I256 to convert
    /// @return signed The signed int128
    function asInt128(I256 _i256) internal pure returns (int128 signed) {
        return int128(I256.unwrap(_i256));
    }

    /// @dev Converts an I256 to a signed int120
    /// @param _i256 The I256 to convert
    /// @return signed The signed int120
    function asInt120(I256 _i256) internal pure returns (int120 signed) {
        return int120(I256.unwrap(_i256));
    }

    /// @dev Converts an I256 to a signed int112
    /// @param _i256 The I256 to convert
    /// @return signed The signed int112
    function asInt112(I256 _i256) internal pure returns (int112 signed) {
        return int112(I256.unwrap(_i256));
    }

    /// @dev Converts an I256 to a signed int104
    /// @param _i256 The I256 to convert
    /// @return signed The signed int104
    function asInt104(I256 _i256) internal pure returns (int104 signed) {
        return int104(I256.unwrap(_i256));
    }

    /// @dev Converts an I256 to a signed int96
    /// @param _i256 The I256 to convert
    /// @return signed The signed int96
    function asInt96(I256 _i256) internal pure returns (int96 signed) {
        return int96(I256.unwrap(_i256));
    }

    /// @dev Converts an I256 to a signed int88
    /// @param _i256 The I256 to convert
    /// @return signed The signed int88
    function asInt88(I256 _i256) internal pure returns (int88 signed) {
        return int88(I256.unwrap(_i256));
    }

    /// @dev Converts an I256 to a signed int80
    /// @param _i256 The I256 to convert
    /// @return signed The signed int80
    function asInt80(I256 _i256) internal pure returns (int80 signed) {
        return int80(I256.unwrap(_i256));
    }

    /// @dev Converts an I256 to a signed int72
    /// @param _i256 The I256 to convert
    /// @return signed The signed int72
    function asInt72(I256 _i256) internal pure returns (int72 signed) {
        return int72(I256.unwrap(_i256));
    }

    /// @dev Converts an I256 to a signed int64
    /// @param _i256 The I256 to convert
    /// @return signed The signed int64
    function asInt64(I256 _i256) internal pure returns (int64 signed) {
        return int64(I256.unwrap(_i256));
    }

    /// @dev Converts an I256 to a signed int56
    /// @param _i256 The I256 to convert
    /// @return signed The signed int56
    function asInt56(I256 _i256) internal pure returns (int56 signed) {
        return int56(I256.unwrap(_i256));
    }

    /// @dev Converts an I256 to a signed int48
    /// @param _i256 The I256 to convert
    /// @return signed The signed int48
    function asInt48(I256 _i256) internal pure returns (int48 signed) {
        return int48(I256.unwrap(_i256));
    }

    /// @dev Converts an I256 to a signed int40
    /// @param _i256 The I256 to convert
    /// @return signed The signed int40
    function asInt40(I256 _i256) internal pure returns (int40 signed) {
        return int40(I256.unwrap(_i256));
    }

    /// @dev Converts an I256 to a signed int32
    /// @param _i256 The I256 to convert
    /// @return signed The signed int32
    function asInt32(I256 _i256) internal pure returns (int32 signed) {
        return int32(I256.unwrap(_i256));
    }

    /// @dev Converts an I256 to a signed int24
    /// @param _i256 The I256 to convert
    /// @return signed The signed int24
    function asInt24(I256 _i256) internal pure returns (int24 signed) {
        return int24(I256.unwrap(_i256));
    }

    /// @dev Converts an I256 to a signed int16
    /// @param _i256 The I256 to convert
    /// @return signed The signed int16
    function asInt16(I256 _i256) internal pure returns (int16 signed) {
        return int16(I256.unwrap(_i256));
    }

    /// @dev Converts an I256 to a signed int8
    /// @param _i256 The I256 to convert
    /// @return signed The signed int8
    function asInt8(I256 _i256) internal pure returns (int8 signed) {
        return int8(I256.unwrap(_i256));
    }

    /// @dev Converts an I256 to an unsigned uint256
    /// @param _i256 The I256 to convert
    /// @return unsigned The unsigned uint256
    function asUint256(I256 _i256) internal pure returns (uint256 unsigned) {
        return uint256(I256.unwrap(_i256));
    }

    /// @dev Converts an I256 to an unsigned uint248
    /// @param _i256 The I256 to convert
    /// @return unsigned The unsigned uint248
    function asUint248(I256 _i256) internal pure returns (uint248 unsigned) {
        return uint248(uint256(I256.unwrap(_i256)));
    }

    /// @dev Converts an I256 to an unsigned uint240
    /// @param _i256 The I256 to convert
    /// @return unsigned The unsigned uint240
    function asUint240(I256 _i256) internal pure returns (uint240 unsigned) {
        return uint240(uint256(I256.unwrap(_i256)));
    }

    /// @dev Converts an I256 to an unsigned uint232
    /// @param _i256 The I256 to convert
    /// @return unsigned The unsigned uint232
    function asUint232(I256 _i256) internal pure returns (uint232 unsigned) {
        return uint232(uint256(I256.unwrap(_i256)));
    }

    /// @dev Converts an I256 to an unsigned uint224
    /// @param _i256 The I256 to convert
    /// @return unsigned The unsigned uint224
    function asUint224(I256 _i256) internal pure returns (uint224 unsigned) {
        return uint224(uint256(I256.unwrap(_i256)));
    }

    /// @dev Converts an I256 to an unsigned uint216
    /// @param _i256 The I256 to convert
    /// @return unsigned The unsigned uint216
    function asUint216(I256 _i256) internal pure returns (uint216 unsigned) {
        return uint216(uint256(I256.unwrap(_i256)));
    }

    /// @dev Converts an I256 to an unsigned uint208
    /// @param _i256 The I256 to convert
    /// @return unsigned The unsigned uint208
    function asUint208(I256 _i256) internal pure returns (uint208 unsigned) {
        return uint208(uint256(I256.unwrap(_i256)));
    }

    /// @dev Converts an I256 to an unsigned uint200
    /// @param _i256 The I256 to convert
    /// @return unsigned The unsigned uint200
    function asUint200(I256 _i256) internal pure returns (uint200 unsigned) {
        return uint200(uint256(I256.unwrap(_i256)));
    }

    /// @dev Converts an I256 to an unsigned uint192
    /// @param _i256 The I256 to convert
    /// @return unsigned The unsigned uint192
    function asUint192(I256 _i256) internal pure returns (uint192 unsigned) {
        return uint192(uint256(I256.unwrap(_i256)));
    }

    /// @dev Converts an I256 to an unsigned uint184
    /// @param _i256 The I256 to convert
    /// @return unsigned The unsigned uint184
    function asUint184(I256 _i256) internal pure returns (uint184 unsigned) {
        return uint184(uint256(I256.unwrap(_i256)));
    }

    /// @dev Converts an I256 to an unsigned uint176
    /// @param _i256 The I256 to convert
    /// @return unsigned The unsigned uint176
    function asUint176(I256 _i256) internal pure returns (uint176 unsigned) {
        return uint176(uint256(I256.unwrap(_i256)));
    }

    /// @dev Converts an I256 to an unsigned uint168
    /// @param _i256 The I256 to convert
    /// @return unsigned The unsigned uint168
    function asUint168(I256 _i256) internal pure returns (uint168 unsigned) {
        return uint168(uint256(I256.unwrap(_i256)));
    }

    /// @dev Converts an I256 to an unsigned uint160
    /// @param _i256 The I256 to convert
    /// @return unsigned The unsigned uint160
    function asUint160(I256 _i256) internal pure returns (uint160 unsigned) {
        return uint160(uint256(I256.unwrap(_i256)));
    }

    /// @dev Converts an I256 to an unsigned uint152
    /// @param _i256 The I256 to convert
    /// @return unsigned The unsigned uint152
    function asUint152(I256 _i256) internal pure returns (uint152 unsigned) {
        return uint152(uint256(I256.unwrap(_i256)));
    }

    /// @dev Converts an I256 to an unsigned uint144
    /// @param _i256 The I256 to convert
    /// @return unsigned The unsigned uint144
    function asUint144(I256 _i256) internal pure returns (uint144 unsigned) {
        return uint144(uint256(I256.unwrap(_i256)));
    }

    /// @dev Converts an I256 to an unsigned uint136
    /// @param _i256 The I256 to convert
    /// @return unsigned The unsigned uint136
    function asUint136(I256 _i256) internal pure returns (uint136 unsigned) {
        return uint136(uint256(I256.unwrap(_i256)));
    }

    /// @dev Converts an I256 to an unsigned uint128
    /// @param _i256 The I256 to convert
    /// @return unsigned The unsigned uint128
    function asUint128(I256 _i256) internal pure returns (uint128 unsigned) {
        return uint128(uint256(I256.unwrap(_i256)));
    }

    /// @dev Converts an I256 to an unsigned uint120
    /// @param _i256 The I256 to convert
    /// @return unsigned The unsigned uint120
    function asUint120(I256 _i256) internal pure returns (uint120 unsigned) {
        return uint120(uint256(I256.unwrap(_i256)));
    }

    /// @dev Converts an I256 to an unsigned uint112
    /// @param _i256 The I256 to convert
    /// @return unsigned The unsigned uint112
    function asUint112(I256 _i256) internal pure returns (uint112 unsigned) {
        return uint112(uint256(I256.unwrap(_i256)));
    }

    /// @dev Converts an I256 to an unsigned uint104
    /// @param _i256 The I256 to convert
    /// @return unsigned The unsigned uint104
    function asUint104(I256 _i256) internal pure returns (uint104 unsigned) {
        return uint104(uint256(I256.unwrap(_i256)));
    }

    /// @dev Converts an I256 to an unsigned uint96
    /// @param _i256 The I256 to convert
    /// @return unsigned The unsigned uint96
    function asUint96(I256 _i256) internal pure returns (uint96 unsigned) {
        return uint96(uint256(I256.unwrap(_i256)));
    }

    /// @dev Converts an I256 to an unsigned uint88
    /// @param _i256 The I256 to convert
    /// @return unsigned The unsigned uint88
    function asUint88(I256 _i256) internal pure returns (uint88 unsigned) {
        return uint88(uint256(I256.unwrap(_i256)));
    }

    /// @dev Converts an I256 to an unsigned uint80
    /// @param _i256 The I256 to convert
    /// @return unsigned The unsigned uint80
    function asUint80(I256 _i256) internal pure returns (uint80 unsigned) {
        return uint80(uint256(I256.unwrap(_i256)));
    }

    /// @dev Converts an I256 to an unsigned uint72
    /// @param _i256 The I256 to convert
    /// @return unsigned The unsigned uint72
    function asUint72(I256 _i256) internal pure returns (uint72 unsigned) {
        return uint72(uint256(I256.unwrap(_i256)));
    }

    /// @dev Converts an I256 to an unsigned uint64
    /// @param _i256 The I256 to convert
    /// @return unsigned The unsigned uint64
    function asUint64(I256 _i256) internal pure returns (uint64 unsigned) {
        return uint64(uint256(I256.unwrap(_i256)));
    }

    /// @dev Converts an I256 to an unsigned uint56
    /// @param _i256 The I256 to convert
    /// @return unsigned The unsigned uint56
    function asUint56(I256 _i256) internal pure returns (uint56 unsigned) {
        return uint56(uint256(I256.unwrap(_i256)));
    }

    /// @dev Converts an I256 to an unsigned uint48
    /// @param _i256 The I256 to convert
    /// @return unsigned The unsigned uint48
    function asUint48(I256 _i256) internal pure returns (uint48 unsigned) {
        return uint48(uint256(I256.unwrap(_i256)));
    }

    /// @dev Converts an I256 to an unsigned uint40
    /// @param _i256 The I256 to convert
    /// @return unsigned The unsigned uint40
    function asUint40(I256 _i256) internal pure returns (uint40 unsigned) {
        return uint40(uint256(I256.unwrap(_i256)));
    }

    /// @dev Converts an I256 to an unsigned uint32
    /// @param _i256 The I256 to convert
    /// @return unsigned The unsigned uint32
    function asUint32(I256 _i256) internal pure returns (uint32 unsigned) {
        return uint32(uint256(I256.unwrap(_i256)));
    }

    /// @dev Converts an I256 to an unsigned uint24
    /// @param _i256 The I256 to convert
    /// @return unsigned The unsigned uint24
    function asUint24(I256 _i256) internal pure returns (uint24 unsigned) {
        return uint24(uint256(I256.unwrap(_i256)));
    }

    /// @dev Converts an I256 to an unsigned uint16
    /// @param _i256 The I256 to convert
    /// @return unsigned The unsigned uint16
    function asUint16(I256 _i256) internal pure returns (uint16 unsigned) {
        return uint16(uint256(I256.unwrap(_i256)));
    }

    /// @dev Converts an I256 to an unsigned uint8
    /// @param _i256 The I256 to convert
    /// @return unsigned The unsigned uint8
    function asUint8(I256 _i256) internal pure returns (uint8 unsigned) {
        return uint8(uint256(I256.unwrap(_i256)));
    }

    /// @dev Adds an int256 to an I256
    /// @param _i256 The I256 to add to
    /// @param _addend The int256 to add
    /// @return i256 The result of the addition
    function add(I256 _i256, int256 _addend) internal pure returns (I256 i256) {
        return I256.wrap(add(I256.unwrap(_i256), _addend));
    }

    /// @dev Subtracts an int256 from an I256
    /// @param _i256 The I256 to subtract from
    /// @param _subtrahend The int256 to subtract
    /// @return i256 The result of the subtraction
    function sub(I256 _i256, int256 _subtrahend) internal pure returns (I256 i256) {
        return I256.wrap(sub(I256.unwrap(_i256), _subtrahend));
    }

    /// @dev Increments an I256
    /// @param _i256 The I256 to increment
    /// @return i256 The result of the increment
    function inc(I256 _i256) internal pure returns (I256 i256) {
        return I256.wrap(inc(I256.unwrap(_i256)));
    }

    /// @dev Decrements an I256
    /// @param _i256 The I256 to decrement
    /// @return i256 The result of the decrement
    function dec(I256 _i256) internal pure returns (I256 i256) {
        return I256.wrap(dec(I256.unwrap(_i256)));
    }

    /// @dev Multiplies an I256 by an int256
    /// @param _i256 The I256 to multiply
    /// @param _multiplier The int256 to multiply by
    /// @return i256 The result of the multiplication
    function mul(I256 _i256, int256 _multiplier) internal pure returns (I256 i256) {
        return I256.wrap(mul(I256.unwrap(_i256), _multiplier));
    }

    /// @dev Divides an I256 by an int256
    /// @param _i256 The I256 to divide
    /// @param _divisor The int256 to divide by
    /// @return i256 The result of the division
    function div(I256 _i256, int256 _divisor) internal pure returns (I256 i256) {
        return I256.wrap(div(I256.unwrap(_i256), _divisor));
    }

    /// @dev Divides an I256 by an int256 and returns the remainder
    /// @param _i256 The I256 to divide
    /// @param _divisor The int256 to divide by
    /// @return i256 The remainder of the division
    function mod(I256 _i256, int256 _divisor) internal pure returns (I256 i256) {
        return I256.wrap(mod(I256.unwrap(_i256), _divisor));
    }

    /// @dev Logical and of an I256 and an int256
    /// @param _i256 The I256 to and
    /// @param _value The int256 to and with
    /// @return i256 The result of the and
    function and(I256 _i256, int256 _value) internal pure returns (I256 i256) {
        return I256.wrap(I256.unwrap(_i256) & _value);
    }

    /// @dev Logical or of an I256 and an int256
    /// @param _i256 The I256 to or
    /// @param _value The int256 to or with
    /// @return i256 The result of the or
    function or(I256 _i256, int256 _value) internal pure returns (I256 i256) {
        return I256.wrap(I256.unwrap(_i256) | _value);
    }

    /// @dev Logical xor of an I256 and an int256
    /// @param _i256 The I256 to xor
    /// @param _value The int256 to xor with
    /// @return i256 The result of the xor
    function xor(I256 _i256, int256 _value) internal pure returns (I256 i256) {
        return I256.wrap(I256.unwrap(_i256) ^ _value);
    }

    /// @dev Logical not of an I256
    /// @param _i256 The I256 to not
    /// @return i256 The result of the not
    function not(I256 _i256) internal pure returns (I256 i256) {
        return I256.wrap(~I256.unwrap(_i256));
    }

    /// @dev Compares an I256 to an int256 for equality
    /// @param _i256 The I256 to compare
    /// @param _value The int256 to compare to
    /// @return equal True if the I256 and int256 are equal
    function eq(I256 _i256, int256 _value) internal pure returns (bool) {
        return I256.unwrap(_i256) == _value;
    }

    /// @dev Compares an I256 to an int256 for inequality
    /// @param _i256 The I256 to compare
    /// @param _value The int256 to compare to
    /// @return equal True if the I256 and int256 are not equal
    function neq(I256 _i256, int256 _value) internal pure returns (bool) {
        return I256.unwrap(_i256) != _value;
    }

    /// @dev Compares an I256 to an int256 for greater than
    /// @param _i256 The I256 to compare
    /// @param _value The int256 to compare to
    /// @return equal True if the I256 is greater than the int256
    function gt(I256 _i256, int256 _value) internal pure returns (bool) {
        return I256.unwrap(_i256) > _value;
    }

    /// @dev Compares an I256 to an int256 for greater than or equal to
    /// @param _i256 The I256 to compare
    /// @param _value The int256 to compare to
    /// @return equal True if the I256 is greater than or equal to the int256
    function gte(I256 _i256, int256 _value) internal pure returns (bool) {
        return I256.unwrap(_i256) >= _value;
    }

    /// @dev Compares an I256 to an int256 for less than
    /// @param _i256 The I256 to compare
    /// @param _value The int256 to compare to
    /// @return equal True if the I256 is less than the int256
    function lt(I256 _i256, int256 _value) internal pure returns (bool) {
        return I256.unwrap(_i256) < _value;
    }

    /// @dev Compares an I256 to an int256 for less than or equal to
    /// @param _i256 The I256 to compare
    /// @param _value The int256 to compare to
    /// @return equal True if the I256 is less than or equal to the int256
    function lte(I256 _i256, int256 _value) internal pure returns (bool) {
        return I256.unwrap(_i256) <= _value;
    }

    /*********************
     * U256 ->
     *********************/

    /// @dev Wraps an int256 into a U256.
    /// @param _i256 The int256 to wrap.
    /// @return u256 The wrapped U256.
    function asU256(int256 _i256) internal pure returns (U256 u256) {
        u256 = U256.wrap(uint256(_i256));
    }

    /// @dev Wraps a uint256 into a U256.
    /// @param _u256 The uint256 to wrap.
    /// @return u256 The wrapped U256.
    function asU256(uint256 _u256) internal pure returns (U256 u256) {
        u256 = U256.wrap(_u256);
    }

    /// @dev Converts a U256 to a uint256.
    /// @param _u256 The U256 to unwrap.
    /// @return unsigned The uint256 representation of the U256.
    function asUint256(U256 _u256) internal pure returns (uint256 unsigned) {
        return U256.unwrap(_u256);
    }

    /// @dev Converts a U256 to a uint224.
    /// @param _u256 The U256 to unwrap.
    /// @return unsigned The uint224 representation of the U256.
    function asUint224(U256 _u256) internal pure returns (uint224 unsigned) {
        return uint224(U256.unwrap(_u256));
    }

    /// @dev Converts a U256 to a uint216.
    /// @param _u256 The U256 to unwrap.
    /// @return unsigned The uint216 representation of the U256.
    function asUint216(U256 _u256) internal pure returns (uint216 unsigned) {
        return uint216(U256.unwrap(_u256));
    }

    /// @dev Converts a U256 to a uint208.
    /// @param _u256 The U256 to unwrap.
    /// @return unsigned The uint208 representation of the U256.
    function asUint208(U256 _u256) internal pure returns (uint208 unsigned) {
        return uint208(U256.unwrap(_u256));
    }

    /// @dev Converts a U256 to a uint200.
    /// @param _u256 The U256 to unwrap.
    /// @return unsigned The uint200 representation of the U256.
    function asUint200(U256 _u256) internal pure returns (uint200 unsigned) {
        return uint200(U256.unwrap(_u256));
    }

    /// @dev Converts a U256 to a uint192.
    /// @param _u256 The U256 to unwrap.
    /// @return unsigned The uint192 representation of the U256.
    function asUint192(U256 _u256) internal pure returns (uint192 unsigned) {
        return uint192(U256.unwrap(_u256));
    }

    /// @dev Converts a U256 to a uint184.
    /// @param _u256 The U256 to unwrap.
    /// @return unsigned The uint184 representation of the U256.
    function asUint184(U256 _u256) internal pure returns (uint184 unsigned) {
        return uint184(U256.unwrap(_u256));
    }

    /// @dev Converts a U256 to a uint176.
    /// @param _u256 The U256 to unwrap.
    /// @return unsigned The uint176 representation of the U256.
    function asUint176(U256 _u256) internal pure returns (uint176 unsigned) {
        return uint176(U256.unwrap(_u256));
    }

    /// @dev Converts a U256 to a uint168.
    /// @param _u256 The U256 to unwrap.
    /// @return unsigned The uint168 representation of the U256.
    function asUint168(U256 _u256) internal pure returns (uint168 unsigned) {
        return uint168(U256.unwrap(_u256));
    }

    /// @dev Converts a U256 to a uint160.
    /// @param _u256 The U256 to unwrap.
    /// @return unsigned The uint160 representation of the U256.
    function asUint160(U256 _u256) internal pure returns (uint160 unsigned) {
        return uint160(U256.unwrap(_u256));
    }

    /// @dev Converts a U256 to a uint152.
    /// @param _u256 The U256 to unwrap.
    /// @return unsigned The uint152 representation of the U256.
    function asUint152(U256 _u256) internal pure returns (uint152 unsigned) {
        return uint152(U256.unwrap(_u256));
    }

    /// @dev Converts a U256 to a uint144.
    /// @param _u256 The U256 to unwrap.
    /// @return unsigned The uint144 representation of the U256.
    function asUint144(U256 _u256) internal pure returns (uint144 unsigned) {
        return uint144(U256.unwrap(_u256));
    }

    /// @dev Converts a U256 to a uint136.
    /// @param _u256 The U256 to unwrap.
    /// @return unsigned The uint136 representation of the U256.
    function asUint136(U256 _u256) internal pure returns (uint136 unsigned) {
        return uint136(U256.unwrap(_u256));
    }

    /// @dev Converts a U256 to a uint128.
    /// @param _u256 The U256 to unwrap.
    /// @return unsigned The uint128 representation of the U256.
    function asUint128(U256 _u256) internal pure returns (uint128 unsigned) {
        return uint128(U256.unwrap(_u256));
    }

    /// @dev Converts a U256 to a uint120.
    /// @param _u256 The U256 to unwrap.
    /// @return unsigned The uint120 representation of the U256.
    function asUint120(U256 _u256) internal pure returns (uint120 unsigned) {
        return uint120(U256.unwrap(_u256));
    }

    /// @dev Converts a U256 to a uint112.
    /// @param _u256 The U256 to unwrap.
    /// @return unsigned The uint112 representation of the U256.
    function asUint112(U256 _u256) internal pure returns (uint112 unsigned) {
        return uint112(U256.unwrap(_u256));
    }

    /// @dev Converts a U256 to a uint104.
    /// @param _u256 The U256 to unwrap.
    /// @return unsigned The uint104 representation of the U256.
    function asUint104(U256 _u256) internal pure returns (uint104 unsigned) {
        return uint104(U256.unwrap(_u256));
    }

    /// @dev Converts a U256 to a uint96.
    /// @param _u256 The U256 to unwrap.
    /// @return unsigned The uint96 representation of the U256.
    function asUint96(U256 _u256) internal pure returns (uint96 unsigned) {
        return uint96(U256.unwrap(_u256));
    }

    /// @dev Converts a U256 to a uint88.
    /// @param _u256 The U256 to unwrap.
    /// @return unsigned The uint88 representation of the U256.
    function asUint88(U256 _u256) internal pure returns (uint88 unsigned) {
        return uint88(U256.unwrap(_u256));
    }

    /// @dev Converts a U256 to a uint80.
    /// @param _u256 The U256 to unwrap.
    /// @return unsigned The uint80 representation of the U256.
    function asUint80(U256 _u256) internal pure returns (uint80 unsigned) {
        return uint80(U256.unwrap(_u256));
    }

    /// @dev Converts a U256 to a uint72.
    /// @param _u256 The U256 to unwrap.
    /// @return unsigned The uint72 representation of the U256.
    function asUint72(U256 _u256) internal pure returns (uint72 unsigned) {
        return uint72(U256.unwrap(_u256));
    }

    /// @dev Converts a U256 to a uint64.
    /// @param _u256 The U256 to unwrap.
    /// @return unsigned The uint64 representation of the U256.
    function asUint64(U256 _u256) internal pure returns (uint64 unsigned) {
        return uint64(U256.unwrap(_u256));
    }

    /// @dev Converts a U256 to a uint56.
    /// @param _u256 The U256 to unwrap.
    /// @return unsigned The uint56 representation of the U256.
    function asUint56(U256 _u256) internal pure returns (uint56 unsigned) {
        return uint56(U256.unwrap(_u256));
    }

    /// @dev Converts a U256 to a uint48.
    /// @param _u256 The U256 to unwrap.
    /// @return unsigned The uint48 representation of the U256.
    function asUint48(U256 _u256) internal pure returns (uint48 unsigned) {
        return uint48(U256.unwrap(_u256));
    }

    /// @dev Converts a U256 to a uint40.
    /// @param _u256 The U256 to unwrap.
    /// @return unsigned The uint40 representation of the U256.
    function asUint40(U256 _u256) internal pure returns (uint40 unsigned) {
        return uint40(U256.unwrap(_u256));
    }

    /// @dev Converts a U256 to a uint32.
    /// @param _u256 The U256 to unwrap.
    /// @return unsigned The uint32 representation of the U256.
    function asUint32(U256 _u256) internal pure returns (uint32 unsigned) {
        return uint32(U256.unwrap(_u256));
    }

    /// @dev Converts a U256 to a uint24.
    /// @param _u256 The U256 to unwrap.
    /// @return unsigned The uint24 representation of the U256.
    function asUint24(U256 _u256) internal pure returns (uint24 unsigned) {
        return uint24(U256.unwrap(_u256));
    }

    /// @dev Converts a U256 to a uint16.
    /// @param _u256 The U256 to unwrap.
    /// @return unsigned The uint16 representation of the U256.
    function asUint16(U256 _u256) internal pure returns (uint16 unsigned) {
        return uint16(U256.unwrap(_u256));
    }

    /// @dev Converts a U256 to a uint8.
    /// @param _u256 The U256 to unwrap.
    /// @return unsigned The uint8 representation of the U256.
    function asUint8(U256 _u256) internal pure returns (uint8 unsigned) {
        return uint8(U256.unwrap(_u256));
    }

    /// @dev Converts a U256 to an int256.
    /// @param _u256 The U256 to convert.
    /// @return signed The int256 representation of the U256.
    function asInt256(U256 _u256) internal pure returns (int256 signed) {
        return int256(U256.unwrap(_u256));
    }

    /// @dev Converts a U256 to an int248.
    /// @param _u256 The U256 to convert.
    /// @return signed The int248 representation of the U256.
    function asInt248(U256 _u256) internal pure returns (int248 signed) {
        return int248(int256(U256.unwrap(_u256)));
    }

    /// @dev Converts a U256 to an int240.
    /// @param _u256 The U256 to convert.
    /// @return signed The int240 representation of the U256.
    function asInt240(U256 _u256) internal pure returns (int240 signed) {
        return int240(int256(U256.unwrap(_u256)));
    }

    /// @dev Converts a U256 to an int232.
    /// @param _u256 The U256 to convert.
    /// @return signed The int232 representation of the U256.
    function asInt232(U256 _u256) internal pure returns (int232 signed) {
        return int232(int256(U256.unwrap(_u256)));
    }

    /// @dev Converts a U256 to an int224.
    /// @param _u256 The U256 to convert.
    /// @return signed The int224 representation of the U256.
    function asInt224(U256 _u256) internal pure returns (int224 signed) {
        return int224(int256(U256.unwrap(_u256)));
    }

    /// @dev Converts a U256 to an int216.
    /// @param _u256 The U256 to convert.
    /// @return signed The int216 representation of the U256.
    function asInt216(U256 _u256) internal pure returns (int216 signed) {
        return int216(int256(U256.unwrap(_u256)));
    }

    /// @dev Converts a U256 to an int208.
    /// @param _u256 The U256 to convert.
    /// @return signed The int208 representation of the U256.
    function asInt208(U256 _u256) internal pure returns (int208 signed) {
        return int208(int256(U256.unwrap(_u256)));
    }

    /// @dev Converts a U256 to an int200.
    /// @param _u256 The U256 to convert.
    /// @return signed The int200 representation of the U256.
    function asInt200(U256 _u256) internal pure returns (int200 signed) {
        return int200(int256(U256.unwrap(_u256)));
    }

    /// @dev Converts a U256 to an int192.
    /// @param _u256 The U256 to convert.
    /// @return signed The int192 representation of the U256.
    function asInt192(U256 _u256) internal pure returns (int192 signed) {
        return int192(int256(U256.unwrap(_u256)));
    }

    /// @dev Converts a U256 to an int184.
    /// @param _u256 The U256 to convert.
    /// @return signed The int184 representation of the U256.
    function asInt184(U256 _u256) internal pure returns (int184 signed) {
        return int184(int256(U256.unwrap(_u256)));
    }

    /// @dev Converts a U256 to an int176.
    /// @param _u256 The U256 to convert.
    /// @return signed The int176 representation of the U256.
    function asInt176(U256 _u256) internal pure returns (int176 signed) {
        return int176(int256(U256.unwrap(_u256)));
    }

    /// @dev Converts a U256 to an int168.
    /// @param _u256 The U256 to convert.
    /// @return signed The int168 representation of the U256.
    function asInt168(U256 _u256) internal pure returns (int168 signed) {
        return int168(int256(U256.unwrap(_u256)));
    }
    
    /// @dev Converts a U256 to an int160.
    /// @param _u256 The U256 to convert.
    /// @return signed The int160 representation of the U256.
    function asInt160(U256 _u256) internal pure returns (int160 signed) {
        return int160(int256(U256.unwrap(_u256)));
    }

    /// @dev Converts a U256 to an int152.
    /// @param _u256 The U256 to convert.
    /// @return signed The int152 representation of the U256.
    function asInt152(U256 _u256) internal pure returns (int152 signed) {
        return int152(int256(U256.unwrap(_u256)));
    }

    /// @dev Converts a U256 to an int144.
    /// @param _u256 The U256 to convert.
    /// @return signed The int144 representation of the U256.
    function asInt144(U256 _u256) internal pure returns (int144 signed) {
        return int144(int256(U256.unwrap(_u256)));
    }

    /// @dev Converts a U256 to an int136.
    /// @param _u256 The U256 to convert.
    /// @return signed The int136 representation of the U256.
    function asInt136(U256 _u256) internal pure returns (int136 signed) {
        return int136(int256(U256.unwrap(_u256)));
    }

    /// @dev Converts a U256 to an int128.
    /// @param _u256 The U256 to convert.
    /// @return signed The int128 representation of the U256.
    function asInt128(U256 _u256) internal pure returns (int128 signed) {
        return int128(int256(U256.unwrap(_u256)));
    }

    /// @dev Converts a U256 to an int120.
    /// @param _u256 The U256 to convert.
    /// @return signed The int120 representation of the U256.
    function asInt120(U256 _u256) internal pure returns (int120 signed) {
        return int120(int256(U256.unwrap(_u256)));
    }

    /// @dev Converts a U256 to an int112.
    /// @param _u256 The U256 to convert.
    /// @return signed The int112 representation of the U256.
    function asInt112(U256 _u256) internal pure returns (int112 signed) {
        return int112(int256(U256.unwrap(_u256)));
    }

    /// @dev Converts a U256 to an int104.
    /// @param _u256 The U256 to convert.
    /// @return signed The int104 representation of the U256.
    function asInt104(U256 _u256) internal pure returns (int104 signed) {
        return int104(int256(U256.unwrap(_u256)));
    }

    /// @dev Converts a U256 to an int96.
    /// @param _u256 The U256 to convert.
    /// @return signed The int96 representation of the U256.
    function asInt96(U256 _u256) internal pure returns (int96 signed) {
        return int96(int256(U256.unwrap(_u256)));
    }

    /// @dev Converts a U256 to an int88.
    /// @param _u256 The U256 to convert.
    /// @return signed The int88 representation of the U256.
    function asInt88(U256 _u256) internal pure returns (int88 signed) {
        return int88(int256(U256.unwrap(_u256)));
    }

    /// @dev Converts a U256 to an int80.
    /// @param _u256 The U256 to convert.
    /// @return signed The int80 representation of the U256.
    function asInt80(U256 _u256) internal pure returns (int80 signed) {
        return int80(int256(U256.unwrap(_u256)));
    }

    /// @dev Converts a U256 to an int72.
    /// @param _u256 The U256 to convert.
    /// @return signed The int72 representation of the U256.
    function asInt72(U256 _u256) internal pure returns (int72 signed) {
        return int72(int256(U256.unwrap(_u256)));
    }

    /// @dev Converts a U256 to an int64.
    /// @param _u256 The U256 to convert.
    /// @return signed The int64 representation of the U256.
    function asInt64(U256 _u256) internal pure returns (int64 signed) {
        return int64(int256(U256.unwrap(_u256)));
    }

    /// @dev Converts a U256 to an int56.
    /// @param _u256 The U256 to convert.
    /// @return signed The int56 representation of the U256.
    function asInt56(U256 _u256) internal pure returns (int56 signed) {
        return int56(int256(U256.unwrap(_u256)));
    }

    /// @dev Converts a U256 to an int48.
    /// @param _u256 The U256 to convert.
    /// @return signed The int48 representation of the U256.
    function asInt48(U256 _u256) internal pure returns (int48 signed) {
        return int48(int256(U256.unwrap(_u256)));
    }

    /// @dev Converts a U256 to an int40.
    /// @param _u256 The U256 to convert.
    /// @return signed The int40 representation of the U256.
    function asInt40(U256 _u256) internal pure returns (int40 signed) {
        return int40(int256(U256.unwrap(_u256)));
    }

    /// @dev Converts a U256 to an int32.
    /// @param _u256 The U256 to convert.
    /// @return signed The int32 representation of the U256.
    function asInt32(U256 _u256) internal pure returns (int32 signed) {
        return int32(int256(U256.unwrap(_u256)));
    }

    /// @dev Converts a U256 to an int24.
    /// @param _u256 The U256 to convert.
    /// @return signed The int24 representation of the U256.
    function asInt24(U256 _u256) internal pure returns (int24 signed) {
        return int24(int256(U256.unwrap(_u256)));
    }

    /// @dev Converts a U256 to an int16.
    /// @param _u256 The U256 to convert.
    /// @return signed The int16 representation of the U256.
    function asInt16(U256 _u256) internal pure returns (int16 signed) {
        return int16(int256(U256.unwrap(_u256)));
    }

    /// @dev Converts a U256 to an int8.
    /// @param _u256 The U256 to convert.
    /// @return signed The int8 representation of the U256.
    function asInt8(U256 _u256) internal pure returns (int8 signed) {
        return int8(int256(U256.unwrap(_u256)));
    }

    /// @dev Adds a uint256 to a U256.
    /// @param _u256 The U256 to add to.
    /// @param _addend The uint256 to add.
    /// @return u256 The U256 result of the addition.
    function add(U256 _u256, uint256 _addend) internal pure returns (U256 u256) {
        u256 = U256.wrap(add(U256.unwrap(_u256), _addend));
    }

    /// @dev Subtracts a uint256 from a U256.
    /// @param _u256 The U256 to subtract from.
    /// @param _subtrahend The uint256 to subtract.
    /// @return u256 The U256 result of the subtraction.
    function sub(U256 _u256, uint256 _subtrahend) internal pure returns (U256 u256) {
        return U256.wrap(sub(U256.unwrap(_u256), _subtrahend));
    }

    /// @dev Increments a U256.
    /// @param _u256 The U256 to increment.
    /// @return u256 The U256 result of the increment.
    function inc(U256 _u256) internal pure returns (U256 u256) {
        return U256.wrap(inc(U256.unwrap(_u256)));
    }

    /// @dev Decrements a U256.
    /// @param _u256 The U256 to decrement.
    /// @return u256 The U256 result of the decrement.
    function dec(U256 _u256) internal pure returns (U256 u256) {
        return U256.wrap(dec(U256.unwrap(_u256)));
    }

    /// @notice Calculate the product of a U256 and a uint256
    /// @param _u256 The U256
    /// @param _multiplier The uint256
    /// @return u256 The product of _u256 and _multiplier
    function mul(U256 _u256, uint256 _multiplier) internal pure returns (U256 u256) {
        return U256.wrap(mul(U256.unwrap(_u256), _multiplier));
    }

    /**
     * @dev Divide a U256 number by a uint256 number.
     * @param _u256 The U256 number to divide.
     * @param _divisor The uint256 number to divide by.
     * @return u256 The result of dividing _u256 by _divisor.
     */
    function div(U256 _u256, uint256 _divisor) internal pure returns (U256 u256) {
        return U256.wrap(div(U256.unwrap(_u256), _divisor));
    }

    /// @dev Get the modulus of a U256 and a uint256
    /// @param _u256 The U256 to be divided
    /// @param _divisor The divisor
    /// @return u256 The result of the modulo operation
    function mod(U256 _u256, uint256 _divisor) internal pure returns (U256 u256) {
        return U256.wrap(mod(U256.unwrap(_u256), _divisor));
    }

    /// @notice Raise a U256 to the power of a uint256
    /// @param _u256 The base
    /// @param _exponent The exponent
    /// @return u256 The result of raising `_u256` to the power of `_exponent`
    function exp(U256 _u256, uint256 _exponent) internal pure returns (U256 u256) {
        return U256.wrap(exp(U256.unwrap(_u256), _exponent));
    }

    /// @dev Right shift a uint256 by a uint256.
    /// @param _u256 uint256 to right shift
    /// @param _shift uint256 to shift by
    /// @return u256 uint256 result of right shift
    function rshift(U256 _u256, U256 _shift) internal pure returns (U256 u256) {
        return U256.wrap(U256.unwrap(_u256) >> U256.unwrap(_shift));
    }

    /// @dev Left shift a U256 by a U256.
    /// @param _u256 U256 to left shift
    /// @param _shift U256 to shift by
    /// @return u256 U256 result of left shift
    function lshift(U256 _u256, U256 _shift) internal pure returns (U256 u256) {
        return U256.wrap(U256.unwrap(_u256) << U256.unwrap(_shift));
    }

    /// @dev Right shift a U256 by a uint256.
    /// @param _u256 U256 to right shift
    /// @param _shift uint256 to shift by
    /// @return u256 U256 result of right shift
    function rshift(U256 _u256, uint256 _shift) internal pure returns (U256 u256) {
        return U256.wrap(U256.unwrap(_u256) >> _shift);
    }

    /// @dev Left shift a U256 by a uint256.
    /// @param _u256 U256 to left shift
    /// @param _shift uint256 to shift by
    /// @return u256 U256 result of left shift
    function lshift(U256 _u256, uint256 _shift) internal pure returns (U256 u256) {
        return U256.wrap(U256.unwrap(_u256) << _shift);
    }

    /// @dev logical and between the input and the value
    /// @param _u256 input
    /// @param _value value
    /// @return u256 the result of the logical and
    function and(U256 _u256, uint256 _value) internal pure returns (U256 u256) {
        return _u256 & U256.wrap(_value);
    }

    /// @dev logical or between the input and the value
    /// @param _u256 input
    /// @param _value value
    /// @return u256 the result of the logical or
    function or(U256 _u256, uint256 _value) internal pure returns (U256 u256) {
        return _u256 | U256.wrap(_value);
    }

    /// @dev logical xor between the input and the value
    /// @param _u256 input
    /// @param _value value
    /// @return u256 the result of the logical xor
    function xor(U256 _u256, uint256 _value) internal pure returns (U256 u256) {
        return _u256 ^ U256.wrap(_value);
    }

    /// @dev logical not of the input
    /// @param _u256 input
    /// @return u256 the result of the logical not
    function not(U256 _u256) internal pure returns (U256 u256) {
        return ~_u256;
    }

    /// @dev Compare a U256 to a uint256 for equality
    /// @param _u256 The U256 to compare
    /// @param _value The uint256 to compare
    /// @return result True if the U256 is equal to the uint256
    function eq(U256 _u256, uint256 _value) internal pure returns (bool result) {
        return U256.unwrap(_u256) == _value;
    }

    /// @dev Compare a U256 to a uint256 for inequality
    /// @param _u256 The U256 to compare
    /// @param _value The uint256 to compare
    /// @return result True if the U256 is not equal to the uint256
    function neq(U256 _u256, uint256 _value) internal pure returns (bool result) {
        return U256.unwrap(_u256) != _value;
    }

    /// @dev Compare a U256 to a uint256 for greater than
    /// @param _u256 The U256 to compare
    /// @param _value The uint256 to compare
    /// @return result True if the U256 is greater than the uint256
    function gt(U256 _u256, uint256 _value) internal pure returns (bool result) {
        return U256.unwrap(_u256) > _value;
    }

    /// @dev Compare a U256 to a uint256 for greater than or equal to
    /// @param _u256 The U256 to compare
    /// @param _value The uint256 to compare
    /// @return result True if the U256 is greater than or equal to the uint256
    function gte(U256 _u256, uint256 _value) internal pure returns (bool result) {
        return U256.unwrap(_u256) >= _value;
    }

    /// @dev Compare a U256 to a uint256 for less than
    /// @param _u256 The U256 to compare
    /// @param _value The uint256 to compare
    /// @return result True if the U256 is less than the uint256
    function lt(U256 _u256, uint256 _value) internal pure returns (bool result) {
        return U256.unwrap(_u256) < _value;
    }

    /// @dev Compare a U256 to a uint256 for less than or equal to
    /// @param _u256 The U256 to compare
    /// @param _value The uint256 to compare
    /// @return result True if the U256 is less than or equal to the uint256
    function lte(U256 _u256, uint256 _value) internal pure returns (bool result) {
        return U256.unwrap(_u256) <= _value;
    }
}

File 5 of 28 : draft-IERC1822Upgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (interfaces/draft-IERC1822.sol)

pragma solidity ^0.8.0;

/**
 * @dev ERC1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified
 * proxy whose upgrades are fully controlled by the current implementation.
 */
interface IERC1822ProxiableUpgradeable {
    /**
     * @dev Returns the storage slot that the proxiable contract assumes is being used to store the implementation
     * address.
     *
     * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks
     * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this
     * function revert if invoked through a proxy.
     */
    function proxiableUUID() external view returns (bytes32);
}

File 6 of 28 : IBeaconUpgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (proxy/beacon/IBeacon.sol)

pragma solidity ^0.8.0;

/**
 * @dev This is the interface that {BeaconProxy} expects of its beacon.
 */
interface IBeaconUpgradeable {
    /**
     * @dev Must return an address that can be used as a delegate call target.
     *
     * {BeaconProxy} will check that this address is a contract.
     */
    function implementation() external view returns (address);
}

File 7 of 28 : StorageSlotUpgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (utils/StorageSlot.sol)

pragma solidity ^0.8.0;

/**
 * @dev Library for reading and writing primitive types to specific storage slots.
 *
 * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.
 * This library helps with reading and writing to such slots without the need for inline assembly.
 *
 * The functions in this library return Slot structs that contain a `value` member that can be used to read or write.
 *
 * Example usage to set ERC1967 implementation slot:
 * ```
 * contract ERC1967 {
 *     bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
 *
 *     function _getImplementation() internal view returns (address) {
 *         return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
 *     }
 *
 *     function _setImplementation(address newImplementation) internal {
 *         require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract");
 *         StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
 *     }
 * }
 * ```
 *
 * _Available since v4.1 for `address`, `bool`, `bytes32`, and `uint256`._
 */
library StorageSlotUpgradeable {
    struct AddressSlot {
        address value;
    }

    struct BooleanSlot {
        bool value;
    }

    struct Bytes32Slot {
        bytes32 value;
    }

    struct Uint256Slot {
        uint256 value;
    }

    /**
     * @dev Returns an `AddressSlot` with member `value` located at `slot`.
     */
    function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
        /// @solidity memory-safe-assembly
        assembly {
            r.slot := slot
        }
    }

    /**
     * @dev Returns an `BooleanSlot` with member `value` located at `slot`.
     */
    function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
        /// @solidity memory-safe-assembly
        assembly {
            r.slot := slot
        }
    }

    /**
     * @dev Returns an `Bytes32Slot` with member `value` located at `slot`.
     */
    function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
        /// @solidity memory-safe-assembly
        assembly {
            r.slot := slot
        }
    }

    /**
     * @dev Returns an `Uint256Slot` with member `value` located at `slot`.
     */
    function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
        /// @solidity memory-safe-assembly
        assembly {
            r.slot := slot
        }
    }
}

File 8 of 28 : actions.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import {Skill, Attire, CombatStyle, CombatStats} from "./misc.sol";
import {GuaranteedReward, RandomReward} from "./rewards.sol";

enum ActionQueueStatus {
  NONE,
  APPEND,
  KEEP_LAST_IN_PROGRESS
}

struct QueuedActionInputV2 {
  Attire attire;
  uint16 actionId;
  uint16 regenerateId; // Food (combat), maybe something for non-combat later
  uint16 choiceId; // Melee/Ranged/Magic (combat), logs, ore (non-combat)
  uint16 rightHandEquipmentTokenId; // Axe/Sword/bow, can be empty
  uint16 leftHandEquipmentTokenId; // Shield, can be empty
  uint24 timespan; // How long to queue the action for
  CombatStyle combatStyle; // specific style of combat
  uint40 petId; // id of the pet (can be empty)
}

struct QueuedActionInput {
  Attire attire;
  uint16 actionId;
  uint16 regenerateId; // Food (combat), maybe something for non-combat later
  uint16 choiceId; // Melee/Ranged/Magic (combat), logs, ore (non-combat)
  uint16 rightHandEquipmentTokenId; // Axe/Sword/bow, can be empty
  uint16 leftHandEquipmentTokenId; // Shield, can be empty
  uint24 timespan; // How long to queue the action for
  CombatStyle combatStyle; // specific style of combat
}

struct QueuedActionExtra {
  uint40 petId; // id of the pet (can be empty)
}

// Can't extend this due to the actionQueue variable in Player struct
struct QueuedAction {
  uint16 actionId;
  uint16 regenerateId; // Food (combat), maybe something for non-combat later
  uint16 choiceId; // Melee/Ranged/Magic (combat), logs, ore (non-combat)
  uint16 rightHandEquipmentTokenId; // Axe/Sword/bow, can be empty
  uint16 leftHandEquipmentTokenId; // Shield, can be empty
  uint24 timespan; // How long to queue the action for
  CombatStyle combatStyle; // specific style of combat
  uint24 prevProcessedTime; // How long the action has been processed for previously
  uint24 prevProcessedXPTime; // How much XP has been gained for this action so far
  uint64 queueId; // id of this queued action
  bytes1 packed; // isValid first bit (not used yet) and hasPet 2nd bit
  uint24 reserved;
}

struct QueuedActionV1 {
  uint16 actionId;
  uint16 regenerateId; // Food (combat), maybe something for non-combat later
  uint16 choiceId; // Melee/Ranged/Magic (combat), logs, ore (non-combat)
  uint16 rightHandEquipmentTokenId; // Axe/Sword/bow, can be empty
  uint16 leftHandEquipmentTokenId; // Shield, can be empty
  uint24 timespan; // How long to queue the action for
  CombatStyle combatStyle; // specific style of combat
  uint24 prevProcessedTime; // How long the action has been processed for previously
  uint24 prevProcessedXPTime; // How much XP has been gained for this action so far
  uint64 queueId; // id of this queued action
  bool isValid; // If we still have the item, TODO: Not used yet
}

// This is only used as an input arg (and events)
struct Action {
  uint16 actionId;
  ActionInfo info;
  GuaranteedReward[] guaranteedRewards;
  RandomReward[] randomRewards;
  CombatStats combatStats;
}

struct ActionV1 {
  uint16 actionId;
  ActionInfoV1 info;
  GuaranteedReward[] guaranteedRewards;
  RandomReward[] randomRewards;
  CombatStats combatStats;
}

struct ActionInfo {
  Skill skill;
  bool isAvailable;
  bool isDynamic;
  bool actionChoiceRequired; // If true, then the user must choose an action choice
  uint24 xpPerHour;
  uint32 minXP;
  uint24 numSpawned; // Mostly for combat, capped respawn rate for xp/drops. Per hour, base 10000
  uint16 handItemTokenIdRangeMin; // Inclusive
  uint16 handItemTokenIdRangeMax; // Inclusive
  uint8 successPercent; // 0-100
  uint8 worldLocation; // 0 is the main starting world
  bool isFullModeOnly;
}

struct ActionInfoV1 {
  Skill skill;
  bool isAvailable;
  bool isDynamic;
  bool actionChoiceRequired; // If true, then the user must choose an action choice
  uint24 xpPerHour;
  uint32 minXP;
  uint24 numSpawned; // Mostly for combat, capped respawn rate for xp/drops. Per hour, base 10000
  uint16 handItemTokenIdRangeMin; // Inclusive
  uint16 handItemTokenIdRangeMax; // Inclusive
  uint8 successPercent; // 0-100
}

// Allows for 2, 4 or 8 hour respawn time
uint constant SPAWN_MUL = 1000;
uint constant RATE_MUL = 1000;
uint constant GUAR_MUL = 10; // Guaranteeded reward multiplier (1 decimal, allows for 2 hour respawn time)

uint constant ACTION_CHOICE_USE_NEW_MIN_SKILL_SECOND_STORAGE_SLOT_BIT = 6;
uint constant ACTION_CHOICE_USE_ALTERNATE_INPUTS_SECOND_STORAGE_SLOT = 5;

File 9 of 28 : all.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

// Types and constants, no external dependencies
import "./actions.sol";
import "./items.sol";
import "./misc.sol";
import "./players.sol";
import "./rewards.sol";
import "./quests.sol";
import "./promotions.sol";
import "./clans.sol";
import "./pets.sol";

File 10 of 28 : clans.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import {IBank} from "../interfaces/IBank.sol";

enum ClanRank {
  NONE, // Not in a clan
  COMMONER, // Member of the clan
  SCOUT, // Invite and kick commoners
  TREASURER, // Can withdraw from bank
  LEADER, // Can edit clan details
  OWNER // Can do everything and transfer ownership
}

enum BattleResultEnum {
  DRAW,
  WIN,
  LOSE
}

struct ClanBattleInfo {
  uint40 lastClanIdAttackOtherClanIdCooldownTimestamp;
  uint8 numReattacks;
  uint40 lastOtherClanIdAttackClanIdCooldownTimestamp;
  uint8 numReattacksOtherClan;
}

// Packed for gas efficiency
struct Vault {
  bool claimed; // Only applies to the first one, if it's claimed without the second one being claimed
  uint40 timestamp;
  uint80 amount;
  uint40 timestamp1;
  uint80 amount1;
}

struct VaultClanInfo {
  IBank bank;
  uint96 totalBrushLocked;
  // New storage slot
  uint40 attackingCooldownTimestamp;
  uint40 assignCombatantsCooldownTimestamp;
  bool currentlyAttacking;
  uint88 gasPaid; // TODO remove in migration
  uint24 defendingVaultsOffset;
  uint40 blockAttacksTimestamp;
  uint8 blockAttacksCooldownHours;
  bool isInMMRArray;
  uint48[] playerIds;
  Vault[] defendingVaults; // Append only, and use defendingVaultsOffset to decide where the real start is
  uint40 superAttackCooldownTimestamp;
}

uint constant MAX_CLAN_COMBATANTS = 20;
uint constant CLAN_WARS_GAS_PRICE_WINDOW_SIZE = 4;

File 11 of 28 : items.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

uint16 constant NONE = 0;

uint16 constant COMBAT_BASE = 2048;
// Melee
uint16 constant SWORD_BASE = COMBAT_BASE;
uint16 constant BRONZE_SWORD = SWORD_BASE;

// Woodcutting (2816 - 3071)
uint16 constant WOODCUTTING_BASE = 2816;
uint16 constant BRONZE_AXE = WOODCUTTING_BASE;

// Firemaking (3328 - 3583)
uint16 constant FIRE_BASE = 3328;
uint16 constant MAGIC_FIRE_STARTER = FIRE_BASE;
uint16 constant FIRE_MAX = FIRE_BASE + 255;

// Fishing (3072 - 3327)
uint16 constant FISHING_BASE = 3072;
uint16 constant NET_STICK = FISHING_BASE;

// Mining (2560 - 2815)
uint16 constant MINING_BASE = 2560;
uint16 constant BRONZE_PICKAXE = MINING_BASE;

// Magic
uint16 constant STAFF_BASE = COMBAT_BASE + 50;
uint16 constant TOTEM_STAFF = STAFF_BASE;

// Ranged
uint16 constant BOW_BASE = COMBAT_BASE + 100;
uint16 constant BASIC_BOW = BOW_BASE;

// Cooked fish
uint16 constant COOKED_FISH_BASE = 11008;
uint16 constant COOKED_FEOLA = COOKED_FISH_BASE + 3;

// Scrolls
uint16 constant SCROLL_BASE = 12032;
uint16 constant SHADOW_SCROLL = SCROLL_BASE;

// Boosts
uint16 constant BOOST_BASE = 12800;
uint16 constant COMBAT_BOOST = BOOST_BASE;
uint16 constant XP_BOOST = BOOST_BASE + 1;
uint16 constant GATHERING_BOOST = BOOST_BASE + 2;
uint16 constant SKILL_BOOST = BOOST_BASE + 3;
uint16 constant ABSENCE_BOOST = BOOST_BASE + 4;
uint16 constant LUCKY_POTION = BOOST_BASE + 5;
uint16 constant LUCK_OF_THE_DRAW = BOOST_BASE + 6;
uint16 constant PRAY_TO_THE_BEARDIE = BOOST_BASE + 7;
uint16 constant PRAY_TO_THE_BEARDIE_2 = BOOST_BASE + 8;
uint16 constant PRAY_TO_THE_BEARDIE_3 = BOOST_BASE + 9;
uint16 constant BOOST_RESERVED_1 = BOOST_BASE + 10;
uint16 constant BOOST_RESERVED_2 = BOOST_BASE + 11;
uint16 constant BOOST_RESERVED_3 = BOOST_BASE + 12;
uint16 constant GO_OUTSIDE = BOOST_BASE + 13;
uint16 constant RAINING_RARES = BOOST_BASE + 14;
uint16 constant CLAN_BOOSTER = BOOST_BASE + 15;
uint16 constant CLAN_BOOSTER_2 = BOOST_BASE + 16;
uint16 constant CLAN_BOOSTER_3 = BOOST_BASE + 17;
uint16 constant BOOST_RESERVED_4 = BOOST_BASE + 18;
uint16 constant BOOST_RESERVED_5 = BOOST_BASE + 19;
uint16 constant BOOST_RESERVED_6 = BOOST_BASE + 20;
uint16 constant BOOST_MAX = 13055;

// Eggs
uint16 constant EGG_BASE = 12544;
uint16 constant SECRET_EGG_1_TIER1 = EGG_BASE;
uint16 constant SECRET_EGG_2_TIER1 = EGG_BASE + 1;
uint16 constant EGG_MAX = 12799;

struct BulkTransferInfo {
  uint[] tokenIds;
  uint[] amounts;
  address to;
}

File 12 of 28 : misc.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

enum BoostType {
  NONE,
  ANY_XP,
  COMBAT_XP,
  NON_COMBAT_XP,
  GATHERING,
  ABSENCE,
  PASSIVE_SKIP_CHANCE,
  // Clan wars
  PVP_BLOCK,
  PVP_REATTACK,
  PVP_SUPER_ATTACK
}

struct Equipment {
  uint16 itemTokenId;
  uint24 amount;
}

enum Skill {
  NONE,
  COMBAT, // This is a helper which incorporates all combat skills, attack <-> magic, defence, health etc
  MELEE,
  RANGED,
  MAGIC,
  DEFENCE,
  HEALTH,
  RESERVED_COMBAT,
  MINING,
  WOODCUTTING,
  FISHING,
  SMITHING,
  THIEVING,
  CRAFTING,
  COOKING,
  FIREMAKING,
  AGILITY,
  ALCHEMY,
  FLETCHING,
  FORGING,
  RESERVED2,
  RESERVED3,
  RESERVED4,
  RESERVED5,
  RESERVED6,
  RESERVED7,
  RESERVED8,
  RESERVED9,
  RESERVED10,
  RESERVED11,
  RESERVED12,
  RESERVED13,
  RESERVED14,
  RESERVED15,
  RESERVED16,
  RESERVED17,
  RESERVED18,
  RESERVED19,
  RESERVED20,
  TRAVELING // Helper Skill for travelling
}

struct Attire {
  uint16 head;
  uint16 neck;
  uint16 body;
  uint16 arms;
  uint16 legs;
  uint16 feet;
  uint16 ring;
  uint16 reserved1;
}

struct CombatStats {
  // From skill points
  int16 melee;
  int16 magic;
  int16 ranged;
  int16 health;
  // These include equipment
  int16 meleeDefence;
  int16 magicDefence;
  int16 rangedDefence;
}

enum CombatStyle {
  NONE,
  ATTACK,
  DEFENCE
}

File 13 of 28 : pets.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import {Skill} from "./misc.sol";

enum PetSkin {
  NONE,
  DEFAULT,
  OG,
  ONEKIN,
  FROST,
  CRYSTAL,
  ANNIV1,
  KRAGSTYR
}

enum PetEnhancementType {
  NONE,
  MELEE,
  MAGIC,
  RANGED,
  DEFENCE,
  HEALTH,
  MELEE_AND_DEFENCE,
  MAGIC_AND_DEFENCE,
  RANGED_AND_DEFENCE
}

struct Pet {
  Skill skillEnhancement1;
  uint8 skillFixedEnhancement1;
  uint8 skillPercentageEnhancement1;
  Skill skillEnhancement2;
  uint8 skillFixedEnhancement2;
  uint8 skillPercentageEnhancement2;
  uint40 lastAssignmentTimestamp;
  address owner; // Will be used as an optimzation to avoid having to look up the owner of the pet in another storage slot
  // 1 byte left in this storage slot
  uint24 baseId;
}

struct BasePetMetadata {
  string description;
  uint8 tier;
  PetSkin skin;
  PetEnhancementType enhancementType;
  Skill skillEnhancement1;
  uint8 skillFixedMin1;
  uint8 skillFixedMax1;
  uint8 skillFixedIncrement1;
  uint8 skillPercentageMin1;
  uint8 skillPercentageMax1;
  uint8 skillPercentageIncrement1;
  uint8 skillMinLevel1;
  Skill skillEnhancement2;
  uint8 skillFixedMin2;
  uint8 skillFixedMax2;
  uint8 skillFixedIncrement2;
  uint8 skillPercentageMin2;
  uint8 skillPercentageMax2;
  uint8 skillPercentageIncrement2;
  uint8 skillMinLevel2;
  uint16 fixedStarThreshold;
  uint16 percentageStarThreshold;
}

File 14 of 28 : players.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import {QueuedAction} from "./actions.sol";
import {Skill, BoostType, CombatStats, Equipment} from "./misc.sol";
import {PlayerQuest} from "./quests.sol";

// 4 bytes for each level. 0x00000000 is the first level, 0x00000054 is the second, etc.
bytes constant XP_BYTES = hex"0000000000000054000000AE0000010E00000176000001E60000025E000002DE00000368000003FD0000049B00000546000005FC000006C000000792000008730000096400000A6600000B7B00000CA400000DE100000F36000010A200001229000013CB0000158B0000176B0000196E00001B9400001DE20000205A000022FF000025D5000028DD00002C1E00002F99000033540000375200003B9A000040300000451900004A5C00004FFF0000560900005C810000637000006ADD000072D100007B570000847900008E42000098BE0000A3F90000B0020000BCE70000CAB80000D9860000E9630000FA6200010C990001201D0001350600014B6F0001637300017D2E000198C10001B64E0001D5F80001F7E600021C430002433B00026CFD000299BE0002C9B30002FD180003342B00036F320003AE730003F23D00043AE3000488BE0004DC2F0005359B000595700005FC2400066A360006E02D00075E990007E6160008774C000912EB0009B9B4000A6C74000B2C06000BF956000CD561000DC134000EBDF3000FCCD40010EF24";

enum EquipPosition {
  NONE,
  HEAD,
  NECK,
  BODY,
  ARMS,
  LEGS,
  FEET,
  RING,
  SPARE2,
  LEFT_HAND,
  RIGHT_HAND,
  BOTH_HANDS,
  QUIVER,
  MAGIC_BAG,
  FOOD,
  AUX, // wood, seeds  etc..
  BOOST_VIAL,
  EXTRA_BOOST_VIAL,
  GLOBAL_BOOST_VIAL,
  CLAN_BOOST_VIAL,
  PASSIVE_BOOST_VIAL,
  LOCKED_VAULT,
  TERRITORY
}

struct Player {
  uint40 currentActionStartTime; // The start time of the first queued action
  Skill currentActionProcessedSkill1; // The skill that the queued action has already gained XP in
  uint24 currentActionProcessedXPGained1; // The amount of XP that the queued action has already gained
  Skill currentActionProcessedSkill2;
  uint24 currentActionProcessedXPGained2;
  uint16 currentActionProcessedFoodConsumed;
  uint16 currentActionProcessedBaseInputItemsConsumedNum; // e.g scrolls, crafting materials etc
  Skill skillBoosted1; // The skill that is boosted
  Skill skillBoosted2; // The second skill that is boosted
  uint56 totalXP;
  Skill currentActionProcessedSkill3;
  uint24 currentActionProcessedXPGained3;
  bytes1 packedData; // Contains worldLocation in first 6 bits (0 is the main starting world), and full mode unlocked in the upper most bit
  // TODO: Can be up to 7
  QueuedAction[] actionQueue;
  string name; // Raw name
}

struct Item {
  EquipPosition equipPosition;
  bytes1 packedData; // 0x1 exists, upper most bit is full mode
  // Can it be transferred?
  bool isTransferable;
  // Food
  uint16 healthRestored;
  // Boost vial
  BoostType boostType;
  uint16 boostValue; // Varies, could be the % increase
  uint24 boostDuration; // How long the effect of the boost last
  // Combat stats
  int16 melee;
  int16 magic;
  int16 ranged;
  int16 meleeDefence;
  int16 magicDefence;
  int16 rangedDefence;
  int16 health;
  // Minimum requirements in this skill to use this item (can be NONE)
  Skill skill;
  uint32 minXP;
}

struct ItemV1 {
  EquipPosition equipPosition;
  bool exists;
  bool isTransferable;
  uint16 healthRestored;
  BoostType boostType;
  uint16 boostValue;
  uint24 boostDuration;
  int16 melee;
  int16 magic;
  int16 ranged;
  int16 meleeDefence;
  int16 magicDefence;
  int16 rangedDefence;
  int16 health;
  Skill skill;
  uint32 minXP;
}

struct ItemOutput {
  EquipPosition equipPosition;
  bool isFullModeOnly;
  bool isTransferable;
  uint16 healthRestored;
  BoostType boostType;
  uint16 boostValue;
  uint24 boostDuration;
  int16 melee;
  int16 magic;
  int16 ranged;
  int16 meleeDefence;
  int16 magicDefence;
  int16 rangedDefence;
  int16 health;
  Skill skill;
  uint32 minXP;
}

// Used for events
struct BoostInfo {
  uint40 startTime;
  uint24 duration;
  uint16 value;
  uint16 itemTokenId; // Get the effect of it
  BoostType boostType;
}

struct PlayerBoostInfo {
  uint40 startTime;
  uint24 duration;
  uint16 value;
  uint16 itemTokenId; // Get the effect of it
  BoostType boostType;
  // Another boost slot (for global/clan boosts this is the "last", for users it is the "extra")
  uint40 extraOrLastStartTime;
  uint24 extraOrLastDuration;
  uint16 extraOrLastValue;
  uint16 extraOrLastItemTokenId;
  BoostType extraOrLastBoostType;
  uint40 cooldown; // Just put here for packing
}

// This is effectively a ratio to produce 1 of outputTokenId.
// Available choices that can be undertaken for an action
struct ActionChoiceInput {
  Skill skill; // Skill that this action choice is related to
  int16 skillDiff; // How much the skill is increased/decreased by this action choice
  uint24 rate; // Rate of output produced per hour (base 1000) 3 decimals
  uint24 xpPerHour;
  uint16[] inputTokenIds;
  uint24[] inputAmounts;
  uint16 outputTokenId;
  uint8 outputAmount;
  uint8 successPercent; // 0-100
  uint16 handItemTokenIdRangeMin; // Inclusive
  uint16 handItemTokenIdRangeMax; // Inclusive
  bool isFullModeOnly;
  Skill[] minSkills; // Skills required to do this action choice
  uint32[] minXPs; // Min XP in the corresponding skills to be able to do this action choice
}

struct ActionChoiceInputV3 {
  Skill skill; // Skill that this action choice is related to
  int16 skillDiff; // How much the skill is increased/decreased by this action choice
  uint24 rate; // Rate of output produced per hour (base 1000) 3 decimals
  uint24 xpPerHour;
  uint16[] inputTokenIds;
  uint8[] inputAmounts;
  uint16 outputTokenId;
  uint8 outputAmount;
  uint8 successPercent; // 0-100
  uint16 handItemTokenIdRangeMin; // Inclusive
  uint16 handItemTokenIdRangeMax; // Inclusive
  bool isFullModeOnly;
  Skill[] minSkills; // Skills required to do this action choice
  uint32[] minXPs; // Min XP in the corresponding skills to be able to do this action choice
}

struct ActionChoiceInputV2 {
  Skill skill; // Skill that this action choice is related to
  uint32 minXP; // Min XP in the skill to be able to do this action choice
  int16 skillDiff; // How much the skill is increased/decreased by this action choice
  uint24 rate; // Rate of output produced per hour (base 1000) 3 decimals
  uint24 xpPerHour;
  uint16 inputTokenId1;
  uint8 inputAmount1;
  uint16 inputTokenId2;
  uint8 inputAmount2;
  uint16 inputTokenId3;
  uint8 inputAmount3;
  uint16 outputTokenId;
  uint8 outputAmount;
  uint8 successPercent; // 0-100
  uint16 handItemTokenIdRangeMin; // Inclusive
  uint16 handItemTokenIdRangeMax; // Inclusive
  bool isFullModeOnly;
}

struct ActionChoice {
  Skill skill; // Skill that this action choice is related to
  uint32 minXP; // Min XP in the skill to be able to do this action choice
  int16 skillDiff; // How much the skill is increased/decreased by this action choice
  uint24 rate; // Rate of output produced per hour (base 1000) 3 decimals
  uint24 xpPerHour;
  uint16 inputTokenId1;
  uint8 inputAmount1;
  uint16 inputTokenId2;
  uint8 inputAmount2;
  uint16 inputTokenId3;
  uint8 inputAmount3;
  uint16 outputTokenId;
  uint8 outputAmount;
  uint8 successPercent; // 0-100
  uint16 handItemTokenIdRangeMin; // Inclusive
  uint16 handItemTokenIdRangeMax; // Inclusive
  // FullMode is last bit, first 6 bits is worldLocation,
  // 2nd last bit is if there are other skills in next storage slot to check,
  // 3rd last bit if the input amounts should be used
  bytes1 packedData;
  bytes1 reserved;
  // Second storage slot
  Skill minSkill2;
  uint32 minXP2;
  Skill minSkill3;
  uint32 minXP3;
  uint24 newInputAmount1; // alternative inputAmount1 which is larger
  uint24 newInputAmount2; // alternative inputAmount2 which is larger
  uint24 newInputAmount3; // alternative inputAmount3 which is larger
}

struct ActionChoiceV2 {
  Skill skill; // Skill that this action choice is related to
  uint32 minXP; // Min XP in the skill to be able to do this action choice
  int16 skillDiff; // How much the skill is increased/decreased by this action choice
  uint24 rate; // Rate of output produced per hour (base 1000) 3 decimals
  uint24 xpPerHour;
  uint16 inputTokenId1;
  uint8 inputAmount1;
  uint16 inputTokenId2;
  uint8 inputAmount2;
  uint16 inputTokenId3;
  uint8 inputAmount3;
  uint16 outputTokenId;
  uint8 outputAmount;
  uint8 successPercent; // 0-100
  uint16 handItemTokenIdRangeMin; // Inclusive
  uint16 handItemTokenIdRangeMax; // Inclusive
  bytes1 packedData; // FullMode is last bit
}

struct ActionChoiceV1 {
  Skill skill;
  uint32 minXP;
  int16 skillDiff;
  uint24 rate;
  uint24 xpPerHour;
  uint16 inputTokenId1;
  uint8 inputAmount1;
  uint16 inputTokenId2;
  uint8 inputAmount2;
  uint16 inputTokenId3;
  uint8 inputAmount3;
  uint16 outputTokenId;
  uint8 outputAmount;
  uint8 successPercent; // 0-100
}

// Must be in the same order as Skill enum
struct PackedXP {
  uint40 melee;
  uint40 ranged;
  uint40 magic;
  uint40 defence;
  uint40 health;
  uint40 reservedCombat;
  bytes2 packedDataIsMaxed; // 2 bits per skill, 1 = first maxed level
  // Next slot
  uint40 mining;
  uint40 woodcutting;
  uint40 fishing;
  uint40 smithing;
  uint40 thieving;
  uint40 crafting;
  bytes2 packedDataIsMaxed1; // 2 bits per skill, 1 = first maxed level
  // Next slot
  uint40 cooking;
  uint40 firemaking;
  uint40 agility;
  uint40 alchemy;
  uint40 fletching;
  uint40 forging;
  bytes2 packedDataIsMaxed2; // 2 bits per skill, 1 = first maxed level
}

struct AvatarInfo {
  string name;
  string description;
  string imageURI;
  Skill[2] startSkills; // Can be NONE
}

struct PastRandomRewardInfo {
  uint64 queueId;
  uint16 itemTokenId;
  uint24 amount;
}

struct PendingQueuedActionEquipmentState {
  uint[] consumedItemTokenIds;
  uint[] consumedAmounts;
  uint[] producedItemTokenIds;
  uint[] producedAmounts;
}

struct PendingQueuedActionMetadata {
  uint32 xpGained; // total xp gained
  uint32 rolls;
  bool died;
  uint16 actionId;
  uint64 queueId;
  uint24 elapsedTime;
  uint24 xpElapsedTime;
}

struct PendingQueuedActionData {
  // The amount of XP that the queued action has already gained
  Skill skill1;
  uint24 xpGained1;
  Skill skill2; // Most likely health
  uint24 xpGained2;
  Skill skill3; // Could come
  uint24 xpGained3;
  // How much food is consumed in the current action so far
  uint16 foodConsumed;
  // How many base consumables are consumed in the current action so far
  uint16 baseInputItemsConsumedNum;
}

struct PendingQueuedActionProcessed {
  // XP gained during this session
  Skill[] skills;
  uint32[] xpGainedSkills;
  // Data for the current action which has been previously processed, this is used to store on the Player
  PendingQueuedActionData currentAction;
}

struct QuestState {
  uint[] consumedItemTokenIds;
  uint[] consumedAmounts;
  uint[] rewardItemTokenIds;
  uint[] rewardAmounts;
  PlayerQuest[] activeQuestInfo;
  uint[] questsCompleted;
  Skill[] skills; // Skills gained XP in
  uint32[] xpGainedSkills; // XP gained in these skills
}

struct LotteryWinnerInfo {
  uint16 lotteryId;
  uint24 raffleId;
  uint16 itemTokenId;
  uint16 amount;
  bool instantConsume;
  uint40 playerId;
}

struct PendingQueuedActionState {
  // These 2 are in sync. Separated to reduce gas/deployment costs as these are passed down many layers.
  PendingQueuedActionEquipmentState[] equipmentStates;
  PendingQueuedActionMetadata[] actionMetadatas;
  QueuedAction[] remainingQueuedActions;
  PastRandomRewardInfo[] producedPastRandomRewards;
  uint[] xpRewardItemTokenIds;
  uint[] xpRewardAmounts;
  uint[] dailyRewardItemTokenIds;
  uint[] dailyRewardAmounts;
  PendingQueuedActionProcessed processedData;
  bytes32 dailyRewardMask;
  QuestState quests;
  uint numPastRandomRewardInstancesToRemove;
  uint8 worldLocation;
  LotteryWinnerInfo lotteryWinner;
}

struct FullAttireBonusInput {
  Skill skill;
  uint8 bonusXPPercent;
  uint8 bonusRewardsPercent; // 3 = 3%
  uint16[5] itemTokenIds; // 0 = head, 1 = body, 2 arms, 3 body, 4 = feet
}

// Contains everything you need to create an item
struct ItemInput {
  CombatStats combatStats;
  uint16 tokenId;
  EquipPosition equipPosition;
  bool isTransferable;
  bool isFullModeOnly;
  // Minimum requirements in this skill
  Skill skill;
  uint32 minXP;
  // Food
  uint16 healthRestored;
  // Boost
  BoostType boostType;
  uint16 boostValue; // Varies, could be the % increase
  uint24 boostDuration; // How long the effect of the boost vial last
  // uri
  string metadataURI;
  string name;
}

uint constant MAX_UNIQUE_TICKETS_ = 64;
uint constant IS_FULL_MODE_BIT = 7;

// Passive/InstantVRF action
uint constant IS_AVAILABLE_BIT = 1;

// Queued action
uint constant HAS_PET_BIT = 1;

File 15 of 28 : promotions.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

enum Promotion {
  NONE,
  STARTER,
  HALLOWEEN_2023,
  XMAS_2023,
  HALLOWEEN_2024,
  HOLIDAY4, // Just have placeholders for now
  HOLIDAY5,
  HOLIDAY6,
  HOLIDAY7,
  HOLIDAY8,
  HOLIDAY9,
  HOLIDAY10
}

enum PromotionMintStatus {
  NONE,
  SUCCESS,
  PROMOTION_ALREADY_CLAIMED,
  ORACLE_NOT_CALLED,
  MINTING_OUTSIDE_AVAILABLE_DATE,
  PLAYER_DOES_NOT_QUALIFY,
  PLAYER_NOT_HIT_ENOUGH_CLAIMS_FOR_STREAK_BONUS
}

struct PromotionInfoInput {
  Promotion promotion;
  uint40 startTime;
  uint40 endTime; // Exclusive
  uint8 numDailyRandomItemsToPick; // Number of items to pick
  uint40 minTotalXP; // Minimum xp required to claim
  uint brushCost; // Cost in brush to start the promotion, max 16mil
  // Special promotion specific (like 1kin)
  uint8 redeemCodeLength; // Length of the redeem code
  bool adminOnly; // Only admins can mint the promotion, like for 1kin (Not used yet)
  bool promotionTiedToUser; // If the promotion is tied to a user
  bool promotionTiedToPlayer; // If the promotion is tied to the player
  bool promotionMustOwnPlayer; // Must own the player to get the promotion
  // Evolution specific
  bool evolvedHeroOnly; // Only allow evolved heroes to claim
  // Multiday specific
  bool isMultiday; // The promotion is multi-day
  uint brushCostMissedDay; // Cost in brush to mint the promotion if they miss a day (in ether), max 25.6 (base 100)
  uint8 numDaysHitNeededForStreakBonus; // How many days to hit for the streak bonus
  uint8 numDaysClaimablePeriodStreakBonus; // If there is a streak bonus, how many days to claim it after the promotion ends. If no final day bonus, set to 0
  uint8 numRandomStreakBonusItemsToPick1; // Number of items to pick for the streak bonus
  uint8 numRandomStreakBonusItemsToPick2; // Number of random items to pick for the streak bonus
  uint16[] randomStreakBonusItemTokenIds1;
  uint32[] randomStreakBonusAmounts1;
  uint16[] randomStreakBonusItemTokenIds2;
  uint32[] randomStreakBonusAmounts2;
  uint16[] guaranteedStreakBonusItemTokenIds;
  uint16[] guaranteedStreakBonusAmounts;
  // Single and multiday
  uint16[] guaranteedItemTokenIds; // Guaranteed items for the promotions each day, if empty then they are handled in a specific way for the promotion like daily rewards
  uint32[] guaranteedAmounts; // Corresponding amounts to the itemTokenIds
  uint16[] randomItemTokenIds; // Possible items for the promotions each day, if empty then they are handled in a specific way for the promotion like daily rewards
  uint32[] randomAmounts; // Corresponding amounts to the randomItemTokenIds
}

struct PromotionInfo {
  Promotion promotion;
  uint40 startTime;
  uint8 numDays;
  uint8 numDailyRandomItemsToPick; // Number of items to pick
  uint40 minTotalXP; // Minimum xp required to claim
  uint24 brushCost; // Cost in brush to mint the promotion (in ether), max 16mil
  // Special promotion specific (like 1kin), could pack these these later
  uint8 redeemCodeLength; // Length of the redeem code
  bool adminOnly; // Only admins can mint the promotion, like for 1kin
  bool promotionTiedToUser; // If the promotion is tied to a user
  bool promotionTiedToPlayer; // If the promotion is tied to the player
  bool promotionMustOwnPlayer; // Must own the player to get the promotion
  // Evolution specific
  bool evolvedHeroOnly; // Only allow evolved heroes to claim
  // Multiday specific
  bool isMultiday; // The promotion is multi-day
  uint8 brushCostMissedDay; // Cost in brush to mint the promotion if they miss a day (in ether), max 25.5, base 100
  uint8 numDaysHitNeededForStreakBonus; // How many days to hit for the streak bonus
  uint8 numDaysClaimablePeriodStreakBonus; // If there is a streak bonus, how many days to claim it after the promotion ends. If no final day bonus, set to 0
  uint8 numRandomStreakBonusItemsToPick1; // Number of items to pick for the streak bonus
  uint8 numRandomStreakBonusItemsToPick2; // Number of random items to pick for the streak bonus
  // Misc
  uint16[] randomStreakBonusItemTokenIds1;
  uint32[] randomStreakBonusAmounts1;
  uint16[] randomStreakBonusItemTokenIds2; // Not used yet
  uint32[] randomStreakBonusAmounts2; // Not used yet
  uint16[] guaranteedStreakBonusItemTokenIds; // Not used yet
  uint16[] guaranteedStreakBonusAmounts; // Not used yet
  // Single and multiday
  uint16[] guaranteedItemTokenIds; // Guaranteed items for the promotions each day, if empty then they are handled in a specific way for the promotion like daily rewards
  uint32[] guaranteedAmounts; // Corresponding amounts to the itemTokenIds
  uint16[] randomItemTokenIds; // Possible items for the promotions each day, if empty then they are handled in a specific way for the promotion like daily rewards
  uint32[] randomAmounts; // Corresponding amounts to the randomItemTokenIds
}

uint constant BRUSH_COST_MISSED_DAY_MUL = 10;

File 16 of 28 : quests.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import {Skill} from "./misc.sol";

struct QuestInput {
  uint16 dependentQuestId; // The quest that must be completed before this one can be started
  uint16 actionId1; // action to do
  uint16 actionNum1; // how many (up to 65535)
  uint16 actionId2; // another action to do
  uint16 actionNum2; // how many (up to 65535)
  uint16 actionChoiceId; // actionChoice to perform
  uint16 actionChoiceNum; // how many to do (base number), (up to 65535)
  Skill skillReward; // The skill to reward XP to
  uint16 skillXPGained; // The amount of XP to give (up to 65535)
  uint16 rewardItemTokenId1; // Reward an item
  uint16 rewardAmount1; // amount of the reward (up to 65535)
  uint16 rewardItemTokenId2; // Reward another item
  uint16 rewardAmount2; // amount of the reward (up to 65535)
  uint16 burnItemTokenId; // Burn an item
  uint16 burnAmount; // amount of the burn (up to 65535)
  uint16 questId; // Unique id for this quest
  bool isFullModeOnly; // If true this quest requires the user be evolved
  uint8 worldLocation; // 0 is the main starting world
}

struct Quest {
  uint16 dependentQuestId; // The quest that must be completed before this one can be started
  uint16 actionId1; // action to do
  uint16 actionNum1; // how many (up to 65535)
  uint16 actionId2; // another action to do
  uint16 actionNum2; // how many (up to 65535)
  uint16 actionChoiceId; // actionChoice to perform
  uint16 actionChoiceNum; // how many to do (base number), (up to 65535)
  Skill skillReward; // The skill to reward XP to
  uint16 skillXPGained; // The amount of XP to give (up to 65535)
  uint16 rewardItemTokenId1; // Reward an item
  uint16 rewardAmount1; // amount of the reward (up to 65535)
  uint16 rewardItemTokenId2; // Reward another item
  uint16 rewardAmount2; // amount of the reward (up to 65535)
  uint16 burnItemTokenId; // Burn an item
  uint16 burnAmount; // amount of the burn (up to 65535)
  uint16 reserved; // Reserved for future use (previously was questId and cleared)
  bytes1 packedData; // FullMode is last bit, first 6 bits is worldLocation
}

struct QuestV1 {
  uint16 dependentQuestId; // The quest that must be completed before this one can be started
  uint16 actionId1; // action to do
  uint16 actionNum1; // how many (up to 65535)
  uint16 actionId2; // another action to do
  uint16 actionNum2; // how many (up to 65535)
  uint16 actionChoiceId; // actionChoice to perform
  uint16 actionChoiceNum; // how many to do (base number), (up to 65535)
  Skill skillReward; // The skill to reward XP to
  uint16 skillXPGained; // The amount of XP to give (up to 65535)
  uint16 rewardItemTokenId1; // Reward an item
  uint16 rewardAmount1; // amount of the reward (up to 65535)
  uint16 rewardItemTokenId2; // Reward another item
  uint16 rewardAmount2; // amount of the reward (up to 65535)
  uint16 burnItemTokenId; // Burn an item
  uint16 burnAmount; // amount of the burn (up to 65535)
  uint16 questId; // Unique id for this quest
  bool isFullModeOnly; // Was requireActionsCompletedBeforeBurning before
}

struct PlayerQuest {
  uint32 questId;
  uint16 actionCompletedNum1;
  uint16 actionCompletedNum2;
  uint16 actionChoiceCompletedNum;
  uint16 burnCompletedAmount;
  bool isFixed;
}

uint constant QUEST_PURSE_STRINGS = 5; // MAKE SURE THIS MATCHES definitions

File 17 of 28 : rewards.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import {BoostType, Equipment} from "./misc.sol";

struct GuaranteedReward {
  uint16 itemTokenId;
  uint16 rate; // num per hour (base 10, 1 decimal) for actions and num per duration for passive actions
}

struct RandomReward {
  uint16 itemTokenId;
  uint16 chance; // out of 65535
  uint8 amount; // out of 255
}

struct PendingRandomReward {
  uint16 actionId;
  uint40 startTime;
  uint24 xpElapsedTime;
  uint64 queueId;
  uint16 boostItemTokenId;
  uint24 elapsedTime;
  uint24 sentinelElapsedTime;
  uint40 boostStartTime; // When the boost was started
  // Full equipment at the time this was generated
  uint8 fullAttireBonusRewardsPercent;
}

struct ActionRewards {
  uint16 guaranteedRewardTokenId1;
  uint16 guaranteedRewardRate1; // Num per hour base 10 (1 decimal) for actions (Max 6553.5 per hour), num per duration for passive actions
  uint16 guaranteedRewardTokenId2;
  uint16 guaranteedRewardRate2;
  uint16 guaranteedRewardTokenId3;
  uint16 guaranteedRewardRate3;
  // Random chance rewards
  uint16 randomRewardTokenId1;
  uint16 randomRewardChance1; // out of 65535
  uint8 randomRewardAmount1; // out of 255
  uint16 randomRewardTokenId2;
  uint16 randomRewardChance2;
  uint8 randomRewardAmount2;
  uint16 randomRewardTokenId3;
  uint16 randomRewardChance3;
  uint8 randomRewardAmount3;
  uint16 randomRewardTokenId4;
  uint16 randomRewardChance4;
  uint8 randomRewardAmount4;
  // No more room!
}

struct XPThresholdReward {
  uint32 xpThreshold;
  Equipment[] rewards;
}

enum InstantVRFActionType {
  NONE,
  GENERIC,
  FORGING,
  EGG
}

struct InstantVRFActionInput {
  uint16 actionId;
  uint16[] inputTokenIds;
  uint24[] inputAmounts;
  bytes data;
  InstantVRFActionType actionType;
  bool isFullModeOnly;
}

struct InstantVRFRandomReward {
  uint16 itemTokenId;
  uint16 chance; // out of 65535
  uint16 amount; // out of 65535
}

uint constant MAX_GUARANTEED_REWARDS_PER_ACTION = 3;
uint constant MAX_RANDOM_REWARDS_PER_ACTION = 4;
uint constant MAX_REWARDS_PER_ACTION = MAX_GUARANTEED_REWARDS_PER_ACTION + MAX_RANDOM_REWARDS_PER_ACTION;
uint constant MAX_CONSUMED_PER_ACTION = 3;
uint constant MAX_QUEST_REWARDS = 2;

uint constant TIER_1_DAILY_REWARD_START_XP = 0;
uint constant TIER_2_DAILY_REWARD_START_XP = 7_650;
uint constant TIER_3_DAILY_REWARD_START_XP = 33_913;
uint constant TIER_4_DAILY_REWARD_START_XP = 195_864;
uint constant TIER_5_DAILY_REWARD_START_XP = 784_726;
uint constant TIER_6_DAILY_REWARD_START_XP = 2_219_451;

// 4 bytes for each threshold, starts at 500 xp in decimal
bytes constant xpRewardBytes = hex"00000000000001F4000003E8000009C40000138800002710000075300000C350000186A00001D4C0000493E0000557300007A120000927C0000B71B0000DBBA0000F424000124F800016E360001B7740001E8480002625A0002932E0002DC6C0";

File 18 of 28 : IBank.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

interface IBank {
  function initialize(uint clanId, address bankRegistry) external;

  function depositToken(address from, uint playerId, address token, uint amount) external;
}

File 19 of 28 : IOracleRewardCB.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

interface IOracleRewardCB {
  function newOracleRandomWords(uint randomWord) external;
}

File 20 of 28 : ISamWitchVRF.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

interface ISamWitchVRF {
  function requestRandomWords(uint numWords, uint callbackGasLimit) external returns (bytes32 requestId);

  function fulfillRandomWords(
    bytes32 requestId,
    address oracle,
    address fulfillAddress,
    uint256 callbackGasLimit,
    uint256 numWords,
    uint256[2] calldata publicKey,
    uint256[4] calldata proof,
    uint256[2] calldata uPoint,
    uint256[4] calldata vComponents
  ) external returns (bool callSuccess);
}

File 21 of 28 : OwnableUpgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)

pragma solidity ^0.8.0;

import "../utils/ContextUpgradeable.sol";
import "../proxy/utils/Initializable.sol";

/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * 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 OwnableUpgradeable is Initializable, ContextUpgradeable {
  address private _owner;

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

  error CallerIsNotOwner();
  error NewOwnerIsZeroAddress();

  /**
   * @dev Initializes the contract setting the deployer as the initial owner.
   */
  function __Ownable_init() internal onlyInitializing {
    __Ownable_init_unchained();
  }

  function __Ownable_init_unchained() internal onlyInitializing {
    _transferOwnership(_msgSender());
  }

  /**
   * @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 {
    if (owner() != _msgSender()) {
      revert CallerIsNotOwner();
    }
  }

  /**
   * @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 {
    if (newOwner == address(0)) {
      revert NewOwnerIsZeroAddress();
    }
    _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);
  }

  /**
   * @dev This empty reserved space is put in place to allow future versions to add new
   * variables without shifting down storage in the inheritance chain.
   * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
   */
  uint256[49] private __gap;
}

File 22 of 28 : ERC1967UpgradeUpgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (proxy/ERC1967/ERC1967Upgrade.sol)

pragma solidity ^0.8.20;

import "@openzeppelin/contracts-upgradeable/proxy/beacon/IBeaconUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/interfaces/draft-IERC1822Upgradeable.sol";
import "../../utils/AddressUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/utils/StorageSlotUpgradeable.sol";
import "../utils/Initializable.sol";

/**
 * @dev This abstract contract provides getters and event emitting update functions for
 * https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots.
 *
 * _Available since v4.1._
 *
 * @custom:oz-upgrades-unsafe-allow delegatecall
 */
abstract contract ERC1967UpgradeUpgradeable is Initializable {
  error NewImplementationIsNotAContract();
  error NewImplementationNotUUPS();
  error UnsupportedProxiableUUID();
  error NewAdminIsZeroAddress();
  error NewBeaconIsNotAContract();
  error BeaconImplementationIsNotAContract();
  error AddressIsNotContract();

  function __ERC1967Upgrade_init() internal onlyInitializing {}

  function __ERC1967Upgrade_init_unchained() internal onlyInitializing {}

  // This is the keccak-256 hash of "eip1967.proxy.rollback" subtracted by 1
  bytes32 private constant _ROLLBACK_SLOT = 0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143;

  /**
   * @dev Storage slot with the address of the current implementation.
   * This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1, and is
   * validated in the constructor.
   */
  bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;

  /**
   * @dev Emitted when the implementation is upgraded.
   */
  event Upgraded(address indexed implementation);

  /**
   * @dev Returns the current implementation address.
   */
  function _getImplementation() internal view returns (address) {
    return StorageSlotUpgradeable.getAddressSlot(_IMPLEMENTATION_SLOT).value;
  }

  /**
   * @dev Stores a new address in the EIP1967 implementation slot.
   */
  function _setImplementation(address newImplementation) private {
    if (!AddressUpgradeable.isContract(newImplementation)) {
      revert NewImplementationIsNotAContract();
    }
    StorageSlotUpgradeable.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
  }

  /**
   * @dev Perform implementation upgrade
   *
   * Emits an {Upgraded} event.
   */
  function _upgradeTo(address newImplementation) internal {
    _setImplementation(newImplementation);
    emit Upgraded(newImplementation);
  }

  /**
   * @dev Perform implementation upgrade with additional setup call.
   *
   * Emits an {Upgraded} event.
   */
  function _upgradeToAndCall(address newImplementation, bytes memory data, bool forceCall) internal {
    _upgradeTo(newImplementation);
    if (data.length > 0 || forceCall) {
      _functionDelegateCall(newImplementation, data);
    }
  }

  /**
   * @dev Perform implementation upgrade with security checks for UUPS proxies, and additional setup call.
   *
   * Emits an {Upgraded} event.
   */
  function _upgradeToAndCallUUPS(address newImplementation, bytes memory data, bool forceCall) internal {
    // Upgrades from old implementations will perform a rollback test. This test requires the new
    // implementation to upgrade back to the old, non-ERC1822 compliant, implementation. Removing
    // this special case will break upgrade paths from old UUPS implementation to new ones.
    if (StorageSlotUpgradeable.getBooleanSlot(_ROLLBACK_SLOT).value) {
      _setImplementation(newImplementation);
    } else {
      try IERC1822ProxiableUpgradeable(newImplementation).proxiableUUID() returns (bytes32 slot) {
        if (slot != _IMPLEMENTATION_SLOT) {
          revert UnsupportedProxiableUUID();
        }
      } catch {
        revert NewImplementationNotUUPS();
      }
      _upgradeToAndCall(newImplementation, data, forceCall);
    }
  }

  /**
   * @dev Storage slot with the admin of the contract.
   * This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1, and is
   * validated in the constructor.
   */
  bytes32 internal constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;

  /**
   * @dev Emitted when the admin account has changed.
   */
  event AdminChanged(address previousAdmin, address newAdmin);

  /**
   * @dev Returns the current admin.
   */
  function _getAdmin() internal view returns (address) {
    return StorageSlotUpgradeable.getAddressSlot(_ADMIN_SLOT).value;
  }

  /**
   * @dev Stores a new address in the EIP1967 admin slot.
   */
  function _setAdmin(address newAdmin) private {
    if (newAdmin == address(0)) {
      revert NewAdminIsZeroAddress();
    }
    StorageSlotUpgradeable.getAddressSlot(_ADMIN_SLOT).value = newAdmin;
  }

  /**
   * @dev Changes the admin of the proxy.
   *
   * Emits an {AdminChanged} event.
   */
  function _changeAdmin(address newAdmin) internal {
    emit AdminChanged(_getAdmin(), newAdmin);
    _setAdmin(newAdmin);
  }

  /**
   * @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy.
   * This is bytes32(uint256(keccak256('eip1967.proxy.beacon')) - 1)) and is validated in the constructor.
   */
  bytes32 internal constant _BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50;

  /**
   * @dev Emitted when the beacon is upgraded.
   */
  event BeaconUpgraded(address indexed beacon);

  /**
   * @dev Returns the current beacon.
   */
  function _getBeacon() internal view returns (address) {
    return StorageSlotUpgradeable.getAddressSlot(_BEACON_SLOT).value;
  }

  /**
   * @dev Stores a new beacon in the EIP1967 beacon slot.
   */
  function _setBeacon(address newBeacon) private {
    if (!AddressUpgradeable.isContract(newBeacon)) {
      revert NewBeaconIsNotAContract();
    }
    if (!AddressUpgradeable.isContract(IBeaconUpgradeable(newBeacon).implementation())) {
      revert BeaconImplementationIsNotAContract();
    }
    StorageSlotUpgradeable.getAddressSlot(_BEACON_SLOT).value = newBeacon;
  }

  /**
   * @dev Perform beacon upgrade with additional setup call. Note: This upgrades the address of the beacon, it does
   * not upgrade the implementation contained in the beacon (see {UpgradeableBeacon-_setImplementation} for that).
   *
   * Emits a {BeaconUpgraded} event.
   */
  function _upgradeBeaconToAndCall(address newBeacon, bytes memory data, bool forceCall) internal {
    _setBeacon(newBeacon);
    emit BeaconUpgraded(newBeacon);
    if (data.length > 0 || forceCall) {
      _functionDelegateCall(IBeaconUpgradeable(newBeacon).implementation(), data);
    }
  }

  /**
   * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
   * but performing a delegate call.
   *
   * _Available since v3.4._
   */
  function _functionDelegateCall(address target, bytes memory data) private returns (bytes memory) {
    if (!AddressUpgradeable.isContract(target)) {
      revert AddressIsNotContract();
    }

    // solhint-disable-next-line avoid-low-level-calls
    (bool success, bytes memory returndata) = target.delegatecall(data);
    return AddressUpgradeable.verifyCallResult(success, returndata, "Address: low-level delegate call failed");
  }

  /**
   * @dev This empty reserved space is put in place to allow future versions to add new
   * variables without shifting down storage in the inheritance chain.
   * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
   */
  uint256[50] private __gap;
}

File 23 of 28 : Initializable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.1) (proxy/utils/Initializable.sol)

pragma solidity ^0.8.20;

import "../../utils/AddressUpgradeable.sol";

/**
 * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
 * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
 * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
 * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
 *
 * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
 * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
 * case an upgrade adds a module that needs to be initialized.
 *
 * For example:
 *
 * [.hljs-theme-light.nopadding]
 * ```
 * contract MyToken is ERC20Upgradeable {
 *     function initialize() initializer public {
 *         __ERC20_init("MyToken", "MTK");
 *     }
 * }
 * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
 *     function initializeV2() reinitializer(2) public {
 *         __ERC20Permit_init("MyToken");
 *     }
 * }
 * ```
 *
 * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
 * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
 *
 * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
 * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
 *
 * [CAUTION]
 * ====
 * Avoid leaving a contract uninitialized.
 *
 * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
 * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
 * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
 *
 * [.hljs-theme-light.nopadding]
 * ```
 * /// @custom:oz-upgrades-unsafe-allow constructor
 * constructor() {
 *     _disableInitializers();
 * }
 * ```
 * ====
 */
abstract contract Initializable {
  error NotInitializing();
  error IsInitializing();
  error AlreadyInitialized();

  /**
   * @dev Indicates that the contract has been initialized.
   * @custom:oz-retyped-from bool
   */
  uint8 private _initialized;

  /**
   * @dev Indicates that the contract is in the process of being initialized.
   */
  bool private _initializing;

  /**
   * @dev Triggered when the contract has been initialized or reinitialized.
   */
  event Initialized(uint8 version);

  /**
   * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
   * `onlyInitializing` functions can be used to initialize parent contracts.
   *
   * Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a
   * constructor.
   *
   * Emits an {Initialized} event.
   */
  modifier initializer() {
    bool isTopLevelCall = !_initializing;

    if (
      !((isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1))
    ) {
      revert AlreadyInitialized();
    }
    _initialized = 1;
    if (isTopLevelCall) {
      _initializing = true;
    }
    _;
    if (isTopLevelCall) {
      _initializing = false;
      emit Initialized(1);
    }
  }

  /**
   * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
   * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
   * used to initialize parent contracts.
   *
   * A reinitializer may be used after the original initialization step. This is essential to configure modules that
   * are added through upgrades and that require initialization.
   *
   * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
   * cannot be nested. If one is invoked in the context of another, execution will revert.
   *
   * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
   * a contract, executing them in the right order is up to the developer or operator.
   *
   * WARNING: setting the version to 255 will prevent any future reinitialization.
   *
   * Emits an {Initialized} event.
   */
  modifier reinitializer(uint8 version) {
    if (!(!_initializing && _initialized < version)) {
      revert AlreadyInitialized();
    }
    _initialized = version;
    _initializing = true;
    _;
    _initializing = false;
    emit Initialized(version);
  }

  /**
   * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
   * {initializer} and {reinitializer} modifiers, directly or indirectly.
   */
  modifier onlyInitializing() {
    if (!_initializing) {
      revert NotInitializing();
    }
    _;
  }

  /**
   * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
   * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
   * to any version. It is recommended to use this to lock implementation contracts that are designed to be called
   * through proxies.
   *
   * Emits an {Initialized} event the first time it is successfully executed.
   */
  function _disableInitializers() internal virtual {
    if (_initializing) {
      revert IsInitializing();
    }
    if (_initialized < type(uint8).max) {
      _initialized = type(uint8).max;
      emit Initialized(type(uint8).max);
    }
  }

  /**
   * @dev Returns the highest version that has been initialized. See {reinitializer}.
   */
  function _getInitializedVersion() internal view returns (uint8) {
    return _initialized;
  }

  /**
   * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
   */
  function _isInitializing() internal view returns (bool) {
    return _initializing;
  }
}

File 24 of 28 : UUPSUpgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (proxy/utils/UUPSUpgradeable.sol)

pragma solidity ^0.8.20;

import {IERC1822ProxiableUpgradeable} from "@openzeppelin/contracts-upgradeable/interfaces/draft-IERC1822Upgradeable.sol";
import {ERC1967UpgradeUpgradeable} from "../ERC1967/ERC1967UpgradeUpgradeable.sol";
import "./Initializable.sol";

/**
 * @dev An upgradeability mechanism designed for UUPS proxies. The functions included here can perform an upgrade of an
 * {ERC1967Proxy}, when this contract is set as the implementation behind such a proxy.
 *
 * A security mechanism ensures that an upgrade does not turn off upgradeability accidentally, although this risk is
 * reinstated if the upgrade retains upgradeability but removes the security mechanism, e.g. by replacing
 * `UUPSUpgradeable` with a custom implementation of upgrades.
 *
 * The {_authorizeUpgrade} function must be overridden to include access restriction to the upgrade mechanism.
 *
 * _Available since v4.1._
 */
abstract contract UUPSUpgradeable is Initializable, IERC1822ProxiableUpgradeable, ERC1967UpgradeUpgradeable {
  error FunctionMustBeCalledThroughDelegateCall();
  error FunctionMustBeCalledThroughActiveProxy();
  error FunctionMustNotBeCalledThroughDelegateCall();

  function __UUPSUpgradeable_init() internal onlyInitializing {}

  function __UUPSUpgradeable_init_unchained() internal onlyInitializing {}

  /// @custom:oz-upgrades-unsafe-allow state-variable-immutable state-variable-assignment
  address private immutable __self = address(this);

  /**
   * @dev Check that the execution is being performed through a delegatecall call and that the execution context is
   * a proxy contract with an implementation (as defined in ERC1967) pointing to self. This should only be the case
   * for UUPS and transparent proxies that are using the current contract as their implementation. Execution of a
   * function through ERC1167 minimal proxies (clones) would not normally pass this test, but is not guaranteed to
   * fail.
   */
  modifier onlyProxy() {
    if (address(this) == __self) {
      revert FunctionMustBeCalledThroughDelegateCall();
    }
    if (_getImplementation() != __self) {
      revert FunctionMustBeCalledThroughActiveProxy();
    }
    _;
  }

  /**
   * @dev Check that the execution is not being performed through a delegate call. This allows a function to be
   * callable on the implementing contract but not through proxies.
   */
  modifier notDelegated() {
    if (address(this) != __self) {
      revert FunctionMustNotBeCalledThroughDelegateCall();
    }
    _;
  }

  /**
   * @dev Implementation of the ERC1822 {proxiableUUID} function. This returns the storage slot used by the
   * implementation. It is used to validate the implementation's compatibility when performing an upgrade.
   *
   * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks
   * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this
   * function revert if invoked through a proxy. This is guaranteed by the `notDelegated` modifier.
   */
  function proxiableUUID() external view virtual override notDelegated returns (bytes32) {
    return _IMPLEMENTATION_SLOT;
  }

  /**
   * @dev Upgrade the implementation of the proxy to `newImplementation`.
   *
   * Calls {_authorizeUpgrade}.
   *
   * Emits an {Upgraded} event.
   */
  function upgradeTo(address newImplementation) external virtual onlyProxy {
    _authorizeUpgrade(newImplementation);
    _upgradeToAndCallUUPS(newImplementation, new bytes(0), false);
  }

  /**
   * @dev Upgrade the implementation of the proxy to `newImplementation`, and subsequently execute the function call
   * encoded in `data`.
   *
   * Calls {_authorizeUpgrade}.
   *
   * Emits an {Upgraded} event.
   */
  function upgradeToAndCall(address newImplementation, bytes memory data) external payable virtual onlyProxy {
    _authorizeUpgrade(newImplementation);
    _upgradeToAndCallUUPS(newImplementation, data, true);
  }

  /**
   * @dev Function that should revert when `msg.sender` is not authorized to upgrade the contract. Called by
   * {upgradeTo} and {upgradeToAndCall}.
   *
   * Normally, this function will use an xref:access.adoc[access control] modifier such as {Ownable-onlyOwner}.
   *
   * ```solidity
   * function _authorizeUpgrade(address) internal override onlyOwner {}
   * ```
   */
  function _authorizeUpgrade(address newImplementation) internal virtual;

  /**
   * @dev This empty reserved space is put in place to allow future versions to add new
   * variables without shifting down storage in the inheritance chain.
   * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
   */
  uint256[50] private __gap;
}

File 25 of 28 : AddressUpgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol)

pragma solidity ^0.8.20;

/**
 * @dev Collection of functions related to the address type
 */
library AddressUpgradeable {
  error RecipientMayHaveReverted();
  error CallToNonContract();
  error InsufficientAllowance();
  error InsufficientBalance();

  /**
   * @dev Returns true if `account` is a contract.
   *
   * [IMPORTANT]
   * ====
   * It is unsafe to assume that an address for which this function returns
   * false is an externally-owned account (EOA) and not a contract.
   *
   * Among others, `isContract` will return false for the following
   * types of addresses:
   *
   *  - an externally-owned account
   *  - a contract in construction
   *  - an address where a contract will be created
   *  - an address where a contract lived, but was destroyed
   * ====
   *
   * [IMPORTANT]
   * ====
   * You shouldn't rely on `isContract` to protect against flash loan attacks!
   *
   * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
   * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
   * constructor.
   * ====
   */
  function isContract(address account) internal view returns (bool) {
    // This method relies on extcodesize/address.code.length, which returns 0
    // for contracts in construction, since the code is only stored at the end
    // of the constructor execution.

    return account.code.length > 0;
  }

  /**
   * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
   * `recipient`, forwarding all available gas and reverting on errors.
   *
   * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
   * of certain opcodes, possibly making contracts go over the 2300 gas limit
   * imposed by `transfer`, making them unable to receive funds via
   * `transfer`. {sendValue} removes this limitation.
   *
   * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
   *
   * IMPORTANT: because control is transferred to `recipient`, care must be
   * taken to not create reentrancy vulnerabilities. Consider using
   * {ReentrancyGuard} or the
   * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
   */
  function sendValue(address payable recipient, uint256 amount) internal {
    if (address(this).balance < amount) {
      revert InsufficientBalance();
    }

    (bool success, ) = recipient.call{value: amount}("");
    if (!success) {
      revert RecipientMayHaveReverted();
    }
  }

  /**
   * @dev Performs a Solidity function call using a low level `call`. A
   * plain `call` is an unsafe replacement for a function call: use this
   * function instead.
   *
   * If `target` reverts with a revert reason, it is bubbled up by this
   * function (like regular Solidity function calls).
   *
   * Returns the raw returned data. To convert to the expected return value,
   * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
   *
   * Requirements:
   *
   * - `target` must be a contract.
   * - calling `target` with `data` must not revert.
   *
   * _Available since v3.1._
   */
  function functionCall(address target, bytes memory data) internal returns (bytes memory) {
    return functionCallWithValue(target, data, 0, "Address: low-level call failed");
  }

  /**
   * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
   * `errorMessage` as a fallback revert reason when `target` reverts.
   *
   * _Available since v3.1._
   */
  function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
    return functionCallWithValue(target, data, 0, errorMessage);
  }

  /**
   * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
   * but also transferring `value` wei to `target`.
   *
   * Requirements:
   *
   * - the calling contract must have an ETH balance of at least `value`.
   * - the called Solidity function must be `payable`.
   *
   * _Available since v3.1._
   */
  function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
    return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
  }

  /**
   * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
   * with `errorMessage` as a fallback revert reason when `target` reverts.
   *
   * _Available since v3.1._
   */
  function functionCallWithValue(
    address target,
    bytes memory data,
    uint256 value,
    string memory errorMessage
  ) internal returns (bytes memory) {
    if (address(this).balance < value) {
      revert InsufficientAllowance();
    }
    (bool success, bytes memory returndata) = target.call{value: value}(data);
    return verifyCallResultFromTarget(target, success, returndata, errorMessage);
  }

  /**
   * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
   * but performing a static call.
   *
   * _Available since v3.3._
   */
  function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
    return functionStaticCall(target, data, "Address: low-level static call failed");
  }

  /**
   * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
   * but performing a static call.
   *
   * _Available since v3.3._
   */
  function functionStaticCall(
    address target,
    bytes memory data,
    string memory errorMessage
  ) internal view returns (bytes memory) {
    (bool success, bytes memory returndata) = target.staticcall(data);
    return verifyCallResultFromTarget(target, success, returndata, errorMessage);
  }

  /**
   * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
   * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
   *
   * _Available since v4.8._
   */
  function verifyCallResultFromTarget(
    address target,
    bool success,
    bytes memory returndata,
    string memory errorMessage
  ) internal view returns (bytes memory) {
    if (success) {
      if (returndata.length == 0) {
        // only check isContract if the call was successful and the return data is empty
        // otherwise we already know that it was a contract
        if (!isContract(target)) {
          revert CallToNonContract();
        }
      }
      return returndata;
    } else {
      _revert(returndata, errorMessage);
    }
  }

  /**
   * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
   * revert reason or using the provided one.
   *
   * _Available since v4.3._
   */
  function verifyCallResult(
    bool success,
    bytes memory returndata,
    string memory errorMessage
  ) internal pure returns (bytes memory) {
    if (success) {
      return returndata;
    } else {
      _revert(returndata, errorMessage);
    }
  }

  function _revert(bytes memory returndata, string memory errorMessage) private pure {
    // Look for revert reason and bubble it up if present
    if (returndata.length > 0) {
      // The easiest way to bubble the revert reason is using memory via assembly
      assembly ("memory-safe") {
        let returndata_size := mload(returndata)
        revert(add(32, returndata), returndata_size)
      }
    } else {
      revert(errorMessage);
    }
  }
}

File 26 of 28 : ContextUpgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)

pragma solidity ^0.8.20;
import "../proxy/utils/Initializable.sol";

/**
 * @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 ContextUpgradeable is Initializable {
  function __Context_init() internal onlyInitializing {}

  function __Context_init_unchained() internal onlyInitializing {}

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

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

  /**
   * @dev This empty reserved space is put in place to allow future versions to add new
   * variables without shifting down storage in the inheritance chain.
   * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
   */
  uint256[50] private __gap;
}

File 27 of 28 : SamWitchVRFConsumerUpgradeable.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import {Initializable} from "./ozUpgradeable/proxy/utils/Initializable.sol";
import {ISamWitchVRF} from "./interfaces/ISamWitchVRF.sol";

// This is useful as a drop in replacement for the VRFConsumerBaseV2Upgradeable from Chainlink keeping storage compatibility
abstract contract SamWitchVRFConsumerUpgradeable is Initializable {
  ISamWitchVRF internal samWitchVRF;
  error CallerNotSamWitchVRF();

  /**
   * @dev Initializes the contract setting the deployer as the initial owner.
   */
  // solhint-disable-next-line func-name-mixedcase
  function __SamWitchVRFConsumerUpgradeable_init(ISamWitchVRF _samWitchVRF) internal onlyInitializing {
    samWitchVRF = _samWitchVRF;
  }

  /// @dev Reverts if the caller is not the SamWitchVRF contract.
  modifier onlySamWitchVRF() {
    if (msg.sender != address(samWitchVRF)) {
      revert CallerNotSamWitchVRF();
    }
    _;
  }
}

File 28 of 28 : WorldLibrary.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import {UnsafeMath, U256} from "@0xdoublesharp/unsafe-math/contracts/UnsafeMath.sol";

// solhint-disable-next-line no-global-import
import "./globals/all.sol";

// This file contains methods for interacting with the World, used to decrease implementation deployment bytecode code.
library WorldLibrary {
  using UnsafeMath for U256;
  using UnsafeMath for uint;

  error InputSpecifiedWithoutAmount();
  error InputAmountsMustBeInOrder();
  error TooManyInputItems();
  error InvalidInputTokenId();
  error LengthMismatch();
  error InputItemNoDuplicates();
  error InvalidSkill();
  error MinimumSkillsNoDuplicates();
  error TooManyMinSkills();
  error OutputAmountCannotBeZero();
  error OutputSpecifiedWithoutAmount();
  error OutputTokenIdCannotBeEmpty();
  error RandomRewardsMustBeInOrder(uint16 chance1, uint16 chance2);
  error RandomRewardNoDuplicates();
  error GuaranteedRewardsNoDuplicates();
  error NotAFactorOf3600();
  error TooManyGuaranteedRewards();
  error TooManyRandomRewards();
  error FirstMinSkillMustBeActionChoiceSkill();

  function checkActionChoice(ActionChoiceInput calldata _actionChoiceInput) external pure {
    uint16[] calldata inputTokenIds = _actionChoiceInput.inputTokenIds;
    uint24[] calldata amounts = _actionChoiceInput.inputAmounts;

    if (inputTokenIds.length > 3) {
      revert TooManyInputItems();
    }
    if (inputTokenIds.length != amounts.length) {
      revert LengthMismatch();
    }

    if (_actionChoiceInput.outputTokenId != NONE && _actionChoiceInput.outputAmount == 0) {
      revert OutputAmountCannotBeZero();
    }
    if (_actionChoiceInput.outputTokenId == NONE && _actionChoiceInput.outputAmount != 0) {
      revert OutputTokenIdCannotBeEmpty();
    }

    for (uint i; i < inputTokenIds.length; ++i) {
      if (inputTokenIds[i] == 0) {
        revert InvalidInputTokenId();
      }
      if (amounts[i] == 0) {
        revert InputSpecifiedWithoutAmount();
      }

      if (i != inputTokenIds.length - 1) {
        if (amounts[i] > amounts[i + 1]) {
          revert InputAmountsMustBeInOrder();
        }
        for (uint j; j < inputTokenIds.length; ++j) {
          if (j != i && inputTokenIds[i] == inputTokenIds[j]) {
            revert InputItemNoDuplicates();
          }
        }
      }
    }

    // Check minimum xp
    Skill[] calldata minSkills = _actionChoiceInput.minSkills;
    uint32[] calldata minXPs = _actionChoiceInput.minXPs;

    // First minSkill must be the same as the action choice skill
    if (minSkills.length > 0 && minSkills[0] != _actionChoiceInput.skill) {
      revert FirstMinSkillMustBeActionChoiceSkill();
    }

    if (minSkills.length > 3) {
      revert TooManyMinSkills();
    }
    if (minSkills.length != minXPs.length) {
      revert LengthMismatch();
    }

    for (uint i; i < minSkills.length; ++i) {
      if (minSkills[i] == Skill.NONE) {
        revert InvalidSkill();
      }
      // Can only be 0 if it's the first one and there is more than one
      if (minXPs[i] == 0 && (i != 0 || minSkills.length == 1)) {
        revert InputSpecifiedWithoutAmount();
      }

      if (i != minSkills.length - 1) {
        for (uint j; j < minSkills.length; ++j) {
          if (j != i && minSkills[i] == minSkills[j]) {
            revert MinimumSkillsNoDuplicates();
          }
        }
      }
    }

    if (_actionChoiceInput.rate != 0) {
      // Check that it is a factor of 3600
      if ((3600 * RATE_MUL) % _actionChoiceInput.rate != 0) {
        revert NotAFactorOf3600();
      }
    }
  }

  function setActionGuaranteedRewards(
    GuaranteedReward[] calldata _guaranteedRewards,
    ActionRewards storage _actionRewards
  ) external {
    uint guaranteedRewardsLength = _guaranteedRewards.length;
    if (guaranteedRewardsLength != 0) {
      _actionRewards.guaranteedRewardTokenId1 = _guaranteedRewards[0].itemTokenId;
      _actionRewards.guaranteedRewardRate1 = _guaranteedRewards[0].rate;
    }
    if (guaranteedRewardsLength > 1) {
      _actionRewards.guaranteedRewardTokenId2 = _guaranteedRewards[1].itemTokenId;
      _actionRewards.guaranteedRewardRate2 = _guaranteedRewards[1].rate;
      if (_actionRewards.guaranteedRewardTokenId1 == _actionRewards.guaranteedRewardTokenId2) {
        revert GuaranteedRewardsNoDuplicates();
      }
    }
    if (guaranteedRewardsLength > 2) {
      _actionRewards.guaranteedRewardTokenId3 = _guaranteedRewards[2].itemTokenId;
      _actionRewards.guaranteedRewardRate3 = _guaranteedRewards[2].rate;

      U256 bounds = guaranteedRewardsLength.dec().asU256();
      for (U256 iter; iter < bounds; iter = iter.inc()) {
        uint i = iter.asUint256();
        if (_guaranteedRewards[i].itemTokenId == _guaranteedRewards[guaranteedRewardsLength.dec()].itemTokenId) {
          revert GuaranteedRewardsNoDuplicates();
        }
      }
    }
    if (guaranteedRewardsLength > 3) {
      revert TooManyGuaranteedRewards();
    }
  }

  // Random rewards have most common one first
  function setActionRandomRewards(RandomReward[] calldata _randomRewards, ActionRewards storage actionReward) external {
    uint randomRewardsLength = _randomRewards.length;
    if (randomRewardsLength != 0) {
      actionReward.randomRewardTokenId1 = _randomRewards[0].itemTokenId;
      actionReward.randomRewardChance1 = _randomRewards[0].chance;
      actionReward.randomRewardAmount1 = _randomRewards[0].amount;
    }
    if (randomRewardsLength > 1) {
      actionReward.randomRewardTokenId2 = _randomRewards[1].itemTokenId;
      actionReward.randomRewardChance2 = _randomRewards[1].chance;
      actionReward.randomRewardAmount2 = _randomRewards[1].amount;

      if (actionReward.randomRewardChance2 > actionReward.randomRewardChance1) {
        revert RandomRewardsMustBeInOrder(_randomRewards[0].chance, _randomRewards[1].chance);
      }
      if (actionReward.randomRewardTokenId1 == actionReward.randomRewardTokenId2) {
        revert RandomRewardNoDuplicates();
      }
    }
    if (randomRewardsLength > 2) {
      actionReward.randomRewardTokenId3 = _randomRewards[2].itemTokenId;
      actionReward.randomRewardChance3 = _randomRewards[2].chance;
      actionReward.randomRewardAmount3 = _randomRewards[2].amount;

      if (actionReward.randomRewardChance3 > actionReward.randomRewardChance2) {
        revert RandomRewardsMustBeInOrder(_randomRewards[1].chance, _randomRewards[2].chance);
      }

      U256 bounds = randomRewardsLength.dec().asU256();
      for (U256 iter; iter < bounds; iter = iter.inc()) {
        uint i = iter.asUint256();
        if (_randomRewards[i].itemTokenId == _randomRewards[randomRewardsLength.dec()].itemTokenId) {
          revert RandomRewardNoDuplicates();
        }
      }
    }
    if (_randomRewards.length > 3) {
      actionReward.randomRewardTokenId4 = _randomRewards[3].itemTokenId;
      actionReward.randomRewardChance4 = _randomRewards[3].chance;
      actionReward.randomRewardAmount4 = _randomRewards[3].amount;
      if (actionReward.randomRewardChance4 > actionReward.randomRewardChance3) {
        revert RandomRewardsMustBeInOrder(_randomRewards[2].chance, _randomRewards[3].chance);
      }
      U256 bounds = _randomRewards.length.dec().asU256();
      for (U256 iter; iter < bounds; iter = iter.inc()) {
        uint i = iter.asUint256();
        if (_randomRewards[i].itemTokenId == _randomRewards[_randomRewards.length - 1].itemTokenId) {
          revert RandomRewardNoDuplicates();
        }
      }
    }

    if (_randomRewards.length > 4) {
      revert TooManyRandomRewards();
    }
  }
}

Settings
{
  "evmVersion": "paris",
  "optimizer": {
    "enabled": true,
    "runs": 1000,
    "details": {
      "yul": true
    }
  },
  "viaIR": true,
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "libraries": {
    "contracts/WorldLibrary.sol": {
      "WorldLibrary": "0x43da95dc00babae5d00ebea2c8088f3f7cd77832"
    }
  }
}

Contract ABI

[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"uint16","name":"actionId","type":"uint16"}],"name":"ActionAlreadyExists","type":"error"},{"inputs":[],"name":"ActionChoiceAlreadyExists","type":"error"},{"inputs":[],"name":"ActionChoiceDoesNotExist","type":"error"},{"inputs":[],"name":"ActionChoiceIdZeroNotAllowed","type":"error"},{"inputs":[],"name":"ActionDoesNotExist","type":"error"},{"inputs":[],"name":"ActionIdZeroNotAllowed","type":"error"},{"inputs":[],"name":"AddressIsNotContract","type":"error"},{"inputs":[],"name":"AlreadyInitialized","type":"error"},{"inputs":[],"name":"BeaconImplementationIsNotAContract","type":"error"},{"inputs":[],"name":"CallbackGasLimitTooHigh","type":"error"},{"inputs":[],"name":"CallerIsNotOwner","type":"error"},{"inputs":[],"name":"CallerNotSamWitchVRF","type":"error"},{"inputs":[],"name":"CanOnlyRequestAfter1DayHasPassed","type":"error"},{"inputs":[{"internalType":"uint256","name":"currentTime","type":"uint256"},{"internalType":"uint256","name":"checkpoint","type":"uint256"}],"name":"CanOnlyRequestAfterTheNextCheckpoint","type":"error"},{"inputs":[],"name":"DynamicActionsCannotBeAdded","type":"error"},{"inputs":[],"name":"DynamicActionsCannotBeSet","type":"error"},{"inputs":[],"name":"FunctionMustBeCalledThroughActiveProxy","type":"error"},{"inputs":[],"name":"FunctionMustBeCalledThroughDelegateCall","type":"error"},{"inputs":[],"name":"FunctionMustNotBeCalledThroughDelegateCall","type":"error"},{"inputs":[],"name":"InvalidReward","type":"error"},{"inputs":[],"name":"IsInitializing","type":"error"},{"inputs":[],"name":"LengthMismatch","type":"error"},{"inputs":[],"name":"MinCannotBeGreaterThanMax","type":"error"},{"inputs":[],"name":"NewAdminIsZeroAddress","type":"error"},{"inputs":[],"name":"NewBeaconIsNotAContract","type":"error"},{"inputs":[],"name":"NewImplementationIsNotAContract","type":"error"},{"inputs":[],"name":"NewImplementationNotUUPS","type":"error"},{"inputs":[],"name":"NewOwnerIsZeroAddress","type":"error"},{"inputs":[],"name":"NoActionChoices","type":"error"},{"inputs":[],"name":"NoValidRandomWord","type":"error"},{"inputs":[],"name":"NonCombatWithActionChoicesCannotHaveBothGuaranteedAndRandomRewards","type":"error"},{"inputs":[],"name":"NotAFactorOf3600","type":"error"},{"inputs":[],"name":"NotInitializing","type":"error"},{"inputs":[],"name":"RandomWordsCannotBeUpdatedYet","type":"error"},{"inputs":[],"name":"RequestAlreadyFulfilled","type":"error"},{"inputs":[],"name":"TooManyRewardsInPool","type":"error"},{"inputs":[],"name":"UnsupportedProxiableUUID","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint16","name":"actionId","type":"uint16"},{"indexed":false,"internalType":"uint16[]","name":"actionChoiceIds","type":"uint16[]"},{"components":[{"internalType":"enum Skill","name":"skill","type":"uint8"},{"internalType":"int16","name":"skillDiff","type":"int16"},{"internalType":"uint24","name":"rate","type":"uint24"},{"internalType":"uint24","name":"xpPerHour","type":"uint24"},{"internalType":"uint16[]","name":"inputTokenIds","type":"uint16[]"},{"internalType":"uint24[]","name":"inputAmounts","type":"uint24[]"},{"internalType":"uint16","name":"outputTokenId","type":"uint16"},{"internalType":"uint8","name":"outputAmount","type":"uint8"},{"internalType":"uint8","name":"successPercent","type":"uint8"},{"internalType":"uint16","name":"handItemTokenIdRangeMin","type":"uint16"},{"internalType":"uint16","name":"handItemTokenIdRangeMax","type":"uint16"},{"internalType":"bool","name":"isFullModeOnly","type":"bool"},{"internalType":"enum Skill[]","name":"minSkills","type":"uint8[]"},{"internalType":"uint32[]","name":"minXPs","type":"uint32[]"}],"indexed":false,"internalType":"struct ActionChoiceInput[]","name":"choices","type":"tuple[]"}],"name":"AddActionChoices","type":"event"},{"anonymous":false,"inputs":[{"components":[{"internalType":"uint16","name":"actionId","type":"uint16"},{"components":[{"internalType":"enum Skill","name":"skill","type":"uint8"},{"internalType":"bool","name":"isAvailable","type":"bool"},{"internalType":"bool","name":"isDynamic","type":"bool"},{"internalType":"bool","name":"actionChoiceRequired","type":"bool"},{"internalType":"uint24","name":"xpPerHour","type":"uint24"},{"internalType":"uint32","name":"minXP","type":"uint32"},{"internalType":"uint24","name":"numSpawned","type":"uint24"},{"internalType":"uint16","name":"handItemTokenIdRangeMin","type":"uint16"},{"internalType":"uint16","name":"handItemTokenIdRangeMax","type":"uint16"},{"internalType":"uint8","name":"successPercent","type":"uint8"},{"internalType":"uint8","name":"worldLocation","type":"uint8"},{"internalType":"bool","name":"isFullModeOnly","type":"bool"}],"internalType":"struct ActionInfo","name":"info","type":"tuple"},{"components":[{"internalType":"uint16","name":"itemTokenId","type":"uint16"},{"internalType":"uint16","name":"rate","type":"uint16"}],"internalType":"struct GuaranteedReward[]","name":"guaranteedRewards","type":"tuple[]"},{"components":[{"internalType":"uint16","name":"itemTokenId","type":"uint16"},{"internalType":"uint16","name":"chance","type":"uint16"},{"internalType":"uint8","name":"amount","type":"uint8"}],"internalType":"struct RandomReward[]","name":"randomRewards","type":"tuple[]"},{"components":[{"internalType":"int16","name":"melee","type":"int16"},{"internalType":"int16","name":"magic","type":"int16"},{"internalType":"int16","name":"ranged","type":"int16"},{"internalType":"int16","name":"health","type":"int16"},{"internalType":"int16","name":"meleeDefence","type":"int16"},{"internalType":"int16","name":"magicDefence","type":"int16"},{"internalType":"int16","name":"rangedDefence","type":"int16"}],"internalType":"struct CombatStats","name":"combatStats","type":"tuple"}],"indexed":false,"internalType":"struct Action[]","name":"actions","type":"tuple[]"}],"name":"AddActions","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"previousAdmin","type":"address"},{"indexed":false,"internalType":"address","name":"newAdmin","type":"address"}],"name":"AdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"beacon","type":"address"}],"name":"BeaconUpgraded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint16","name":"actionId","type":"uint16"},{"indexed":false,"internalType":"uint16[]","name":"actionChoiceIds","type":"uint16[]"},{"components":[{"internalType":"enum Skill","name":"skill","type":"uint8"},{"internalType":"int16","name":"skillDiff","type":"int16"},{"internalType":"uint24","name":"rate","type":"uint24"},{"internalType":"uint24","name":"xpPerHour","type":"uint24"},{"internalType":"uint16[]","name":"inputTokenIds","type":"uint16[]"},{"internalType":"uint24[]","name":"inputAmounts","type":"uint24[]"},{"internalType":"uint16","name":"outputTokenId","type":"uint16"},{"internalType":"uint8","name":"outputAmount","type":"uint8"},{"internalType":"uint8","name":"successPercent","type":"uint8"},{"internalType":"uint16","name":"handItemTokenIdRangeMin","type":"uint16"},{"internalType":"uint16","name":"handItemTokenIdRangeMax","type":"uint16"},{"internalType":"bool","name":"isFullModeOnly","type":"bool"},{"internalType":"enum Skill[]","name":"minSkills","type":"uint8[]"},{"internalType":"uint32[]","name":"minXPs","type":"uint32[]"}],"indexed":false,"internalType":"struct ActionChoiceInput[]","name":"choices","type":"tuple[]"}],"name":"EditActionChoices","type":"event"},{"anonymous":false,"inputs":[{"components":[{"internalType":"uint16","name":"actionId","type":"uint16"},{"components":[{"internalType":"enum Skill","name":"skill","type":"uint8"},{"internalType":"bool","name":"isAvailable","type":"bool"},{"internalType":"bool","name":"isDynamic","type":"bool"},{"internalType":"bool","name":"actionChoiceRequired","type":"bool"},{"internalType":"uint24","name":"xpPerHour","type":"uint24"},{"internalType":"uint32","name":"minXP","type":"uint32"},{"internalType":"uint24","name":"numSpawned","type":"uint24"},{"internalType":"uint16","name":"handItemTokenIdRangeMin","type":"uint16"},{"internalType":"uint16","name":"handItemTokenIdRangeMax","type":"uint16"},{"internalType":"uint8","name":"successPercent","type":"uint8"},{"internalType":"uint8","name":"worldLocation","type":"uint8"},{"internalType":"bool","name":"isFullModeOnly","type":"bool"}],"internalType":"struct ActionInfo","name":"info","type":"tuple"},{"components":[{"internalType":"uint16","name":"itemTokenId","type":"uint16"},{"internalType":"uint16","name":"rate","type":"uint16"}],"internalType":"struct GuaranteedReward[]","name":"guaranteedRewards","type":"tuple[]"},{"components":[{"internalType":"uint16","name":"itemTokenId","type":"uint16"},{"internalType":"uint16","name":"chance","type":"uint16"},{"internalType":"uint8","name":"amount","type":"uint8"}],"internalType":"struct RandomReward[]","name":"randomRewards","type":"tuple[]"},{"components":[{"internalType":"int16","name":"melee","type":"int16"},{"internalType":"int16","name":"magic","type":"int16"},{"internalType":"int16","name":"ranged","type":"int16"},{"internalType":"int16","name":"health","type":"int16"},{"internalType":"int16","name":"meleeDefence","type":"int16"},{"internalType":"int16","name":"magicDefence","type":"int16"},{"internalType":"int16","name":"rangedDefence","type":"int16"}],"internalType":"struct CombatStats","name":"combatStats","type":"tuple"}],"indexed":false,"internalType":"struct Action[]","name":"actions","type":"tuple[]"}],"name":"EditActions","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint16","name":"actionId","type":"uint16"},{"indexed":false,"internalType":"uint16[]","name":"actionChoiceIds","type":"uint16[]"}],"name":"RemoveActionChoices","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"requestId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"randomWord","type":"uint256"}],"name":"RequestFulfilled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"requestId","type":"uint256"},{"indexed":false,"internalType":"uint32","name":"numWords","type":"uint32"},{"indexed":false,"internalType":"uint256","name":"lastRandomWordsUpdatedTime","type":"uint256"}],"name":"RequestSent","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"implementation","type":"address"}],"name":"Upgraded","type":"event"},{"inputs":[],"name":"MIN_RANDOM_WORDS_UPDATE_TIME","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"NUM_DAYS_RANDOM_WORDS_INITIALIZED","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"actionId","type":"uint256"}],"name":"actions","outputs":[{"internalType":"enum Skill","name":"skill","type":"uint8"},{"internalType":"bool","name":"isAvailable","type":"bool"},{"internalType":"bool","name":"isDynamic","type":"bool"},{"internalType":"bool","name":"actionChoiceRequired","type":"bool"},{"internalType":"uint24","name":"xpPerHour","type":"uint24"},{"internalType":"uint32","name":"minXP","type":"uint32"},{"internalType":"uint24","name":"numSpawned","type":"uint24"},{"internalType":"uint16","name":"handItemTokenIdRangeMin","type":"uint16"},{"internalType":"uint16","name":"handItemTokenIdRangeMax","type":"uint16"},{"internalType":"uint8","name":"successPercent","type":"uint8"},{"internalType":"uint8","name":"worldLocation","type":"uint8"},{"internalType":"bool","name":"isFullModeOnly","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"_actionId","type":"uint16"},{"internalType":"uint16[]","name":"_actionChoiceIds","type":"uint16[]"},{"components":[{"internalType":"enum Skill","name":"skill","type":"uint8"},{"internalType":"int16","name":"skillDiff","type":"int16"},{"internalType":"uint24","name":"rate","type":"uint24"},{"internalType":"uint24","name":"xpPerHour","type":"uint24"},{"internalType":"uint16[]","name":"inputTokenIds","type":"uint16[]"},{"internalType":"uint24[]","name":"inputAmounts","type":"uint24[]"},{"internalType":"uint16","name":"outputTokenId","type":"uint16"},{"internalType":"uint8","name":"outputAmount","type":"uint8"},{"internalType":"uint8","name":"successPercent","type":"uint8"},{"internalType":"uint16","name":"handItemTokenIdRangeMin","type":"uint16"},{"internalType":"uint16","name":"handItemTokenIdRangeMax","type":"uint16"},{"internalType":"bool","name":"isFullModeOnly","type":"bool"},{"internalType":"enum Skill[]","name":"minSkills","type":"uint8[]"},{"internalType":"uint32[]","name":"minXPs","type":"uint32[]"}],"internalType":"struct ActionChoiceInput[]","name":"_actionChoices","type":"tuple[]"}],"name":"addActionChoices","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint16","name":"actionId","type":"uint16"},{"components":[{"internalType":"enum Skill","name":"skill","type":"uint8"},{"internalType":"bool","name":"isAvailable","type":"bool"},{"internalType":"bool","name":"isDynamic","type":"bool"},{"internalType":"bool","name":"actionChoiceRequired","type":"bool"},{"internalType":"uint24","name":"xpPerHour","type":"uint24"},{"internalType":"uint32","name":"minXP","type":"uint32"},{"internalType":"uint24","name":"numSpawned","type":"uint24"},{"internalType":"uint16","name":"handItemTokenIdRangeMin","type":"uint16"},{"internalType":"uint16","name":"handItemTokenIdRangeMax","type":"uint16"},{"internalType":"uint8","name":"successPercent","type":"uint8"},{"internalType":"uint8","name":"worldLocation","type":"uint8"},{"internalType":"bool","name":"isFullModeOnly","type":"bool"}],"internalType":"struct ActionInfo","name":"info","type":"tuple"},{"components":[{"internalType":"uint16","name":"itemTokenId","type":"uint16"},{"internalType":"uint16","name":"rate","type":"uint16"}],"internalType":"struct GuaranteedReward[]","name":"guaranteedRewards","type":"tuple[]"},{"components":[{"internalType":"uint16","name":"itemTokenId","type":"uint16"},{"internalType":"uint16","name":"chance","type":"uint16"},{"internalType":"uint8","name":"amount","type":"uint8"}],"internalType":"struct RandomReward[]","name":"randomRewards","type":"tuple[]"},{"components":[{"internalType":"int16","name":"melee","type":"int16"},{"internalType":"int16","name":"magic","type":"int16"},{"internalType":"int16","name":"ranged","type":"int16"},{"internalType":"int16","name":"health","type":"int16"},{"internalType":"int16","name":"meleeDefence","type":"int16"},{"internalType":"int16","name":"magicDefence","type":"int16"},{"internalType":"int16","name":"rangedDefence","type":"int16"}],"internalType":"struct CombatStats","name":"combatStats","type":"tuple"}],"internalType":"struct Action[]","name":"_actions","type":"tuple[]"}],"name":"addActions","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16[]","name":"_actionIds","type":"uint16[]"},{"internalType":"uint16[][]","name":"_actionChoiceIds","type":"uint16[][]"},{"components":[{"internalType":"enum Skill","name":"skill","type":"uint8"},{"internalType":"int16","name":"skillDiff","type":"int16"},{"internalType":"uint24","name":"rate","type":"uint24"},{"internalType":"uint24","name":"xpPerHour","type":"uint24"},{"internalType":"uint16[]","name":"inputTokenIds","type":"uint16[]"},{"internalType":"uint24[]","name":"inputAmounts","type":"uint24[]"},{"internalType":"uint16","name":"outputTokenId","type":"uint16"},{"internalType":"uint8","name":"outputAmount","type":"uint8"},{"internalType":"uint8","name":"successPercent","type":"uint8"},{"internalType":"uint16","name":"handItemTokenIdRangeMin","type":"uint16"},{"internalType":"uint16","name":"handItemTokenIdRangeMax","type":"uint16"},{"internalType":"bool","name":"isFullModeOnly","type":"bool"},{"internalType":"enum Skill[]","name":"minSkills","type":"uint8[]"},{"internalType":"uint32[]","name":"minXPs","type":"uint32[]"}],"internalType":"struct ActionChoiceInput[][]","name":"_actionChoices","type":"tuple[][]"}],"name":"addBulkActionChoices","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tier","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"dailyRewardPool","outputs":[{"internalType":"uint16","name":"itemTokenId","type":"uint16"},{"internalType":"uint24","name":"amount","type":"uint24"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"_actionId","type":"uint16"},{"internalType":"uint16[]","name":"_actionChoiceIds","type":"uint16[]"},{"components":[{"internalType":"enum Skill","name":"skill","type":"uint8"},{"internalType":"int16","name":"skillDiff","type":"int16"},{"internalType":"uint24","name":"rate","type":"uint24"},{"internalType":"uint24","name":"xpPerHour","type":"uint24"},{"internalType":"uint16[]","name":"inputTokenIds","type":"uint16[]"},{"internalType":"uint24[]","name":"inputAmounts","type":"uint24[]"},{"internalType":"uint16","name":"outputTokenId","type":"uint16"},{"internalType":"uint8","name":"outputAmount","type":"uint8"},{"internalType":"uint8","name":"successPercent","type":"uint8"},{"internalType":"uint16","name":"handItemTokenIdRangeMin","type":"uint16"},{"internalType":"uint16","name":"handItemTokenIdRangeMax","type":"uint16"},{"internalType":"bool","name":"isFullModeOnly","type":"bool"},{"internalType":"enum Skill[]","name":"minSkills","type":"uint8[]"},{"internalType":"uint32[]","name":"minXPs","type":"uint32[]"}],"internalType":"struct ActionChoiceInput[]","name":"_actionChoices","type":"tuple[]"}],"name":"editActionChoices","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint16","name":"actionId","type":"uint16"},{"components":[{"internalType":"enum Skill","name":"skill","type":"uint8"},{"internalType":"bool","name":"isAvailable","type":"bool"},{"internalType":"bool","name":"isDynamic","type":"bool"},{"internalType":"bool","name":"actionChoiceRequired","type":"bool"},{"internalType":"uint24","name":"xpPerHour","type":"uint24"},{"internalType":"uint32","name":"minXP","type":"uint32"},{"internalType":"uint24","name":"numSpawned","type":"uint24"},{"internalType":"uint16","name":"handItemTokenIdRangeMin","type":"uint16"},{"internalType":"uint16","name":"handItemTokenIdRangeMax","type":"uint16"},{"internalType":"uint8","name":"successPercent","type":"uint8"},{"internalType":"uint8","name":"worldLocation","type":"uint8"},{"internalType":"bool","name":"isFullModeOnly","type":"bool"}],"internalType":"struct ActionInfo","name":"info","type":"tuple"},{"components":[{"internalType":"uint16","name":"itemTokenId","type":"uint16"},{"internalType":"uint16","name":"rate","type":"uint16"}],"internalType":"struct GuaranteedReward[]","name":"guaranteedRewards","type":"tuple[]"},{"components":[{"internalType":"uint16","name":"itemTokenId","type":"uint16"},{"internalType":"uint16","name":"chance","type":"uint16"},{"internalType":"uint8","name":"amount","type":"uint8"}],"internalType":"struct RandomReward[]","name":"randomRewards","type":"tuple[]"},{"components":[{"internalType":"int16","name":"melee","type":"int16"},{"internalType":"int16","name":"magic","type":"int16"},{"internalType":"int16","name":"ranged","type":"int16"},{"internalType":"int16","name":"health","type":"int16"},{"internalType":"int16","name":"meleeDefence","type":"int16"},{"internalType":"int16","name":"magicDefence","type":"int16"},{"internalType":"int16","name":"rangedDefence","type":"int16"}],"internalType":"struct CombatStats","name":"combatStats","type":"tuple"}],"internalType":"struct Action[]","name":"_actions","type":"tuple[]"}],"name":"editActions","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_requestId","type":"bytes32"},{"internalType":"uint256[]","name":"_randomWords","type":"uint256[]"}],"name":"fulfillRandomWords","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"_actionId","type":"uint16"},{"internalType":"uint16","name":"_choiceId","type":"uint16"}],"name":"getActionChoice","outputs":[{"components":[{"internalType":"enum Skill","name":"skill","type":"uint8"},{"internalType":"uint32","name":"minXP","type":"uint32"},{"internalType":"int16","name":"skillDiff","type":"int16"},{"internalType":"uint24","name":"rate","type":"uint24"},{"internalType":"uint24","name":"xpPerHour","type":"uint24"},{"internalType":"uint16","name":"inputTokenId1","type":"uint16"},{"internalType":"uint8","name":"inputAmount1","type":"uint8"},{"internalType":"uint16","name":"inputTokenId2","type":"uint16"},{"internalType":"uint8","name":"inputAmount2","type":"uint8"},{"internalType":"uint16","name":"inputTokenId3","type":"uint16"},{"internalType":"uint8","name":"inputAmount3","type":"uint8"},{"internalType":"uint16","name":"outputTokenId","type":"uint16"},{"internalType":"uint8","name":"outputAmount","type":"uint8"},{"internalType":"uint8","name":"successPercent","type":"uint8"},{"internalType":"uint16","name":"handItemTokenIdRangeMin","type":"uint16"},{"internalType":"uint16","name":"handItemTokenIdRangeMax","type":"uint16"},{"internalType":"bytes1","name":"packedData","type":"bytes1"},{"internalType":"bytes1","name":"reserved","type":"bytes1"},{"internalType":"enum Skill","name":"minSkill2","type":"uint8"},{"internalType":"uint32","name":"minXP2","type":"uint32"},{"internalType":"enum Skill","name":"minSkill3","type":"uint8"},{"internalType":"uint32","name":"minXP3","type":"uint32"},{"internalType":"uint24","name":"newInputAmount1","type":"uint24"},{"internalType":"uint24","name":"newInputAmount2","type":"uint24"},{"internalType":"uint24","name":"newInputAmount3","type":"uint24"}],"internalType":"struct ActionChoice","name":"choice","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_actionId","type":"uint256"}],"name":"getActionInfo","outputs":[{"components":[{"internalType":"enum Skill","name":"skill","type":"uint8"},{"internalType":"bool","name":"isAvailable","type":"bool"},{"internalType":"bool","name":"isDynamic","type":"bool"},{"internalType":"bool","name":"actionChoiceRequired","type":"bool"},{"internalType":"uint24","name":"xpPerHour","type":"uint24"},{"internalType":"uint32","name":"minXP","type":"uint32"},{"internalType":"uint24","name":"numSpawned","type":"uint24"},{"internalType":"uint16","name":"handItemTokenIdRangeMin","type":"uint16"},{"internalType":"uint16","name":"handItemTokenIdRangeMax","type":"uint16"},{"internalType":"uint8","name":"successPercent","type":"uint8"},{"internalType":"uint8","name":"worldLocation","type":"uint8"},{"internalType":"bool","name":"isFullModeOnly","type":"bool"}],"internalType":"struct ActionInfo","name":"info","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_actionId","type":"uint256"}],"name":"getActionRewards","outputs":[{"components":[{"internalType":"uint16","name":"guaranteedRewardTokenId1","type":"uint16"},{"internalType":"uint16","name":"guaranteedRewardRate1","type":"uint16"},{"internalType":"uint16","name":"guaranteedRewardTokenId2","type":"uint16"},{"internalType":"uint16","name":"guaranteedRewardRate2","type":"uint16"},{"internalType":"uint16","name":"guaranteedRewardTokenId3","type":"uint16"},{"internalType":"uint16","name":"guaranteedRewardRate3","type":"uint16"},{"internalType":"uint16","name":"randomRewardTokenId1","type":"uint16"},{"internalType":"uint16","name":"randomRewardChance1","type":"uint16"},{"internalType":"uint8","name":"randomRewardAmount1","type":"uint8"},{"internalType":"uint16","name":"randomRewardTokenId2","type":"uint16"},{"internalType":"uint16","name":"randomRewardChance2","type":"uint16"},{"internalType":"uint8","name":"randomRewardAmount2","type":"uint8"},{"internalType":"uint16","name":"randomRewardTokenId3","type":"uint16"},{"internalType":"uint16","name":"randomRewardChance3","type":"uint16"},{"internalType":"uint8","name":"randomRewardAmount3","type":"uint8"},{"internalType":"uint16","name":"randomRewardTokenId4","type":"uint16"},{"internalType":"uint16","name":"randomRewardChance4","type":"uint16"},{"internalType":"uint8","name":"randomRewardAmount4","type":"uint8"}],"internalType":"struct ActionRewards","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"_actionId","type":"uint16"}],"name":"getActionSuccessPercentAndMinXP","outputs":[{"internalType":"uint8","name":"successPercent","type":"uint8"},{"internalType":"uint32","name":"minXP","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tier","type":"uint256"},{"internalType":"uint256","name":"_playerId","type":"uint256"}],"name":"getActiveDailyAndWeeklyRewards","outputs":[{"components":[{"internalType":"uint16","name":"itemTokenId","type":"uint16"},{"internalType":"uint24","name":"amount","type":"uint24"}],"internalType":"struct Equipment[8]","name":"rewards","type":"tuple[8]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"_actionId","type":"uint16"}],"name":"getCombatStats","outputs":[{"components":[{"internalType":"int16","name":"melee","type":"int16"},{"internalType":"int16","name":"magic","type":"int16"},{"internalType":"int16","name":"ranged","type":"int16"},{"internalType":"int16","name":"health","type":"int16"},{"internalType":"int16","name":"meleeDefence","type":"int16"},{"internalType":"int16","name":"magicDefence","type":"int16"},{"internalType":"int16","name":"rangedDefence","type":"int16"}],"internalType":"struct CombatStats","name":"stats","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tier","type":"uint256"},{"internalType":"uint256","name":"_playerId","type":"uint256"}],"name":"getDailyReward","outputs":[{"internalType":"uint256","name":"itemTokenId","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_timestamp","type":"uint256"}],"name":"getMultipleWords","outputs":[{"internalType":"uint256[4]","name":"words","type":"uint256[4]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"_actionId","type":"uint16"}],"name":"getNumSpawn","outputs":[{"internalType":"uint256","name":"numSpawned","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_numTickets","type":"uint256"},{"internalType":"uint256","name":"_startTimestamp","type":"uint256"},{"internalType":"uint256","name":"_endTimestamp","type":"uint256"},{"internalType":"uint256","name":"_playerId","type":"uint256"}],"name":"getRandomBytes","outputs":[{"internalType":"bytes","name":"b","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_timestamp","type":"uint256"}],"name":"getRandomWord","outputs":[{"internalType":"uint256","name":"randomWord","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"_actionId","type":"uint16"}],"name":"getRewardsHelper","outputs":[{"components":[{"internalType":"uint16","name":"guaranteedRewardTokenId1","type":"uint16"},{"internalType":"uint16","name":"guaranteedRewardRate1","type":"uint16"},{"internalType":"uint16","name":"guaranteedRewardTokenId2","type":"uint16"},{"internalType":"uint16","name":"guaranteedRewardRate2","type":"uint16"},{"internalType":"uint16","name":"guaranteedRewardTokenId3","type":"uint16"},{"internalType":"uint16","name":"guaranteedRewardRate3","type":"uint16"},{"internalType":"uint16","name":"randomRewardTokenId1","type":"uint16"},{"internalType":"uint16","name":"randomRewardChance1","type":"uint16"},{"internalType":"uint8","name":"randomRewardAmount1","type":"uint8"},{"internalType":"uint16","name":"randomRewardTokenId2","type":"uint16"},{"internalType":"uint16","name":"randomRewardChance2","type":"uint16"},{"internalType":"uint8","name":"randomRewardAmount2","type":"uint8"},{"internalType":"uint16","name":"randomRewardTokenId3","type":"uint16"},{"internalType":"uint16","name":"randomRewardChance3","type":"uint16"},{"internalType":"uint8","name":"randomRewardAmount3","type":"uint8"},{"internalType":"uint16","name":"randomRewardTokenId4","type":"uint16"},{"internalType":"uint16","name":"randomRewardChance4","type":"uint16"},{"internalType":"uint8","name":"randomRewardAmount4","type":"uint8"}],"internalType":"struct ActionRewards","name":"","type":"tuple"},{"internalType":"enum Skill","name":"skill","type":"uint8"},{"internalType":"uint256","name":"numSpanwed","type":"uint256"},{"internalType":"uint8","name":"worldLocation","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_actionId","type":"uint256"}],"name":"getSkill","outputs":[{"internalType":"enum Skill","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tier","type":"uint256"},{"internalType":"uint256","name":"_playerId","type":"uint256"},{"internalType":"uint256","name":"_day","type":"uint256"},{"internalType":"uint256","name":"_randomWord","type":"uint256"}],"name":"getSpecificDailyReward","outputs":[{"internalType":"uint16","name":"itemTokenId","type":"uint16"},{"internalType":"uint24","name":"amount","type":"uint24"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tier","type":"uint256"},{"internalType":"uint256","name":"_playerId","type":"uint256"}],"name":"getWeeklyReward","outputs":[{"internalType":"uint16","name":"itemTokenId","type":"uint16"},{"internalType":"uint24","name":"amount","type":"uint24"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"_actionId","type":"uint16"},{"internalType":"uint16","name":"_actionChoiceId","type":"uint16"}],"name":"getXPPerHour","outputs":[{"internalType":"uint24","name":"xpPerHour","type":"uint24"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_timestamp","type":"uint256"}],"name":"hasRandomWord","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_vrf","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"lastRandomWordsUpdatedTime","outputs":[{"internalType":"uint40","name":"","type":"uint40"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"proxiableUUID","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"requestId","type":"uint256"}],"name":"randomWords","outputs":[{"internalType":"uint256","name":"randomWord","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"_actionId","type":"uint16"},{"internalType":"uint16[]","name":"_actionChoiceIds","type":"uint16[]"}],"name":"removeActionChoices","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"requestIds","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"requestRandomWords","outputs":[{"internalType":"uint256","name":"requestId","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_gasLimit","type":"uint256"}],"name":"setCallbackGasLimit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tier","type":"uint256"},{"components":[{"internalType":"uint16","name":"itemTokenId","type":"uint16"},{"internalType":"uint24","name":"amount","type":"uint24"}],"internalType":"struct Equipment[]","name":"_dailyRewards","type":"tuple[]"}],"name":"setDailyRewardPool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IOracleRewardCB","name":"_quests","type":"address"}],"name":"setQuests","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_vrf","type":"address"}],"name":"setVRF","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tier","type":"uint256"},{"components":[{"internalType":"uint16","name":"itemTokenId","type":"uint16"},{"internalType":"uint24","name":"amount","type":"uint24"}],"internalType":"struct Equipment[]","name":"_weeklyRewards","type":"tuple[]"}],"name":"setWeeklyRewardPool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IOracleRewardCB","name":"_wishingWell","type":"address"}],"name":"setWishingWell","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"thisWeeksRandomWordSegment","outputs":[{"internalType":"bytes8","name":"","type":"bytes8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newImplementation","type":"address"}],"name":"upgradeTo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newImplementation","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"upgradeToAndCall","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tier","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"weeklyRewardPool","outputs":[{"internalType":"uint16","name":"itemTokenId","type":"uint16"},{"internalType":"uint24","name":"amount","type":"uint24"}],"stateMutability":"view","type":"function"}]

60a080604052346200009e57306080526000549060ff8260081c166200008f575060ff8082161062000053575b6040516159f69081620000a4823960805181818161277e0152818161287501526130bc0152f35b60ff90811916176000557f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498602060405160ff8152a1386200002c565b63ce446e0f60e01b8152600490fd5b600080fdfe610220604052600436101561001357600080fd5b60003560e01c80631929f7b31461335757806322793d2814613340578063264c73521461326b5780632dc918c2146132285780633659cfe61461309657806336f15ed71461304e5780634a2f04a114612f575780634ad8c52914612b0a5780634f1ef286146127f857806352d1902d14612763578063582e5452146125ff5780635f9e245e146125135780636528f09a146124f557806371315901146124b2578063715018a61461245757806374db3052146123d7578063770d0441146123bb5780637fe4cf6b1461227a57806381ab74511461223d57806383240f83146121775780638693ef18146120565780638796ba8c1461201f57806388b33c5b14611f855780638a54942f14611ee65780638da5cb5b14611ebf5780638eafc36414611e8d57806395016e4b14611e56578063b8987a6e14611973578063bbea74f41461147b578063bd880fae14611445578063be52e34f14611378578063beff730f1461134c578063c4d66de814610fa2578063cc3172a114610dd0578063cc76b91114610daa578063d42da17214610c72578063d623d54c14610c16578063dd56f38b14610b4d578063debde28414610b28578063e0c8628914610940578063e5df71fc146108f9578063e63e9b91146107aa578063e87df97214610767578063f2fde38b14610702578063f5a62e191461069f578063f691689c146103325763fb2bbc7f1461022257600080fd5b3461032d5761023036613651565b919061023a61586f565b60ff8311610303578160005260d590602082815261025b60406000206157bd565b60005b85811061026757005b61ffff61027d6102788389876142cd565b614278565b161580156102e2575b6102b8576102b390856000528483526102ae60406000206102a8838a886142cd565b906157f2565b613843565b61025e565b60046040517f28829e82000000000000000000000000000000000000000000000000000000008152fd5b5062ffffff6102fc836102f6848a886142cd565b01614287565b1615610286565b60046040517f2862b710000000000000000000000000000000000000000000000000000000008152fd5b600080fd5b3461032d57604036600319011261032d5761032061034e613395565b6103566133a6565b61ffff610361613b22565b921660005260d060205261ffff604060002091166000526020526040600020805461038f60ff821684613b16565b63ffffffff8160081c1660208401528060281c60010b604084015262ffffff8160381c16606084015262ffffff8160501c16608084015261ffff8160681c1660a084015260ff8160781c1660c084015261ffff8160801c1660e084015260ff8160901c1661010084015261ffff8160981c1661012084015260ff8160a81c1661014084015261ffff8160b01c1661016084015260ff8160c01c1661018084015260ff8160c81c166101a084015261ffff8160d01c166101c084015261ffff8160e01c166101e08401526001600160f81b03198160081b166102008401526001808260f61c161490811561068e575b50610618575b5060405190610493828251613581565b63ffffffff6020820151166020830152604081015160010b604083015262ffffff606082015116606083015262ffffff608082015116608083015261ffff60a08201511660a083015260ff60c08201511660c083015261ffff60e08201511660e083015260ff6101008201511661010083015261ffff6101208201511661012083015260ff6101408201511661014083015261ffff6101608201511661016083015260ff6101808201511661018083015260ff6101a0820151166101a083015261ffff6101c0820151166101c083015261ffff6101e0820151166101e08301526001600160f81b0319610200820151166102008301526102206001600160f81b03198183015116908301526105b16102408083015190840190613581565b61026063ffffffff8183015116908301526105d56102808083015190840190613581565b6102a063ffffffff8183015116908301526102c062ffffff8183015116908301526102e062ffffff81830151169083015262ffffff610300809201511690820152f35b600162ffffff91015461063260ff82166102408501613b16565b63ffffffff8160081c1661026084015261065660ff8260281c166102808501613b16565b63ffffffff8160301c166102a0840152818160501c166102c0840152818160681c166102e084015260801c1661030082015282610483565b60019150819060f51c16148461047d565b3461032d57602036600319011261032d576106b86133f7565b6106c061586f565b75ffffffffffffffffffffffffffffffffffffffff00001975ffffffffffffffffffffffffffffffffffffffff00006000549260101b16911617600055600080f35b3461032d57602036600319011261032d5761071b6133f7565b61072361586f565b6001600160a01b0381161561073d5761073b906158ad565b005b60046040517f7448fbae000000000000000000000000000000000000000000000000000000008152fd5b3461032d57602036600319011261032d576004356001600160a01b03811680910361032d5761079461586f565b6001600160a01b031960d654161760d655600080f35b3461032d5760208060031936011261032d5760043567ffffffffffffffff811161032d576107dc9036906004016133c6565b906107e561586f565b81805b610822576040517fe0c485464feab584463337a60a5f3b30eeae5d466aa5ce2d973b306518e576a6908061081d868683613f74565b0390a1005b6000190161ffff6108368183168585613eb2565b906108436060830161426b565b6108cf578061085183614278565b1660005260cc865260ff6040600020541660288110156108b95761087f575061087a8291614358565b6107e8565b61088a602492614278565b6040517fd44e9bef00000000000000000000000000000000000000000000000000000000815291166004820152fd5b634e487b7160e01b600052602160045260246000fd5b60046040517fccdd1ab5000000000000000000000000000000000000000000000000000000008152fd5b3461032d5760208060031936011261032d5761091660043561392a565b604051916000835b6004821061092b57608085f35b8280600192865181520194019101909261091e565b3461032d57600036600319011261032d5760c9548015159081610af6575b50610acc5760cb5464ffffffffff6201518081831601818111610ab6571690428211610a7f576000916001600160a01b03835460101c1662ffffff604051937f1b739ef10000000000000000000000000000000000000000000000000000000085526001600486015260b81c1660248401528260448160209687945af1918215610a7357600092610a43575b5060607f643b454d39972ed209afefa4a771c7a9057229bc7e6b66566f5be8441bf9b1e291610a1884613706565b8064ffffffffff1960cb54161760cb55604051908482526001868301526040820152a1604051908152f35b9091508281813d8311610a6c575b610a5b8183613543565b8101031261032d57519060606109ea565b503d610a51565b6040513d6000823e3d90fd5b604482604051907f1351c9400000000000000000000000000000000000000000000000000000000082524260048301526024820152fd5b634e487b7160e01b600052601160045260246000fd5b60046040517f974b4f8a000000000000000000000000000000000000000000000000000000008152fd5b600019810191508111610ab657610b0c906135ec565b90549060031b1c60005260ca602052604060002054158161095e565b3461032d57600036600319011261032d57602064ffffffffff60cb5416604051908152f35b3461032d57610b5b36613651565b9190610b6561586f565b60ff8311610303578160005260d4906020828152610b8660406000206157bd565b60005b858110610b9257005b61ffff610ba36102788389876142cd565b16158015610bfb575b8015610bda575b6102b857610bd590856000528483526102ae60406000206102a8838a886142cd565b610b89565b5062ffffff600a81610bf1856102f6868c8a6142cd565b1606161515610bb3565b5062ffffff610c0f836102f6848a886142cd565b1615610bac565b3461032d57610c243661337f565b9060005260d56020526040600020805482101561032d57610c6e91610c4891613639565b50546040805161ffff8316815260109290921c62ffffff16602083015290918291820190565b0390f35b3461032d57610c803661337f565b6040519167ffffffffffffffff61010080850182811186821017610d945760405260005b818110610d6657505060cb5460781c1660005b60078110610d225784610cca858561374f565b60e08301519262ffffff9384602093168382015261ffff8094169052604051938491906000925b60088410610cff5761020087f35b846040600192848387518b81511684520151168382015201930193019291610cf1565b8061ffff610d3584610d619488886137c5565b9190610d41848a613852565b519262ffffff6020610d53878d613852565b510191169052169052613843565b610cb7565b60405190604082019180831085841117610d9457602092604052600081526000838201528188015201610ca4565b634e487b7160e01b600052604160045260246000fd5b3461032d57602036600319011261032d576020610dc86004356138dd565b604051908152f35b3461032d57602036600319011261032d576000610160604051610df281613498565b8281528260208201528260408201528260608201528260808201528260a08201528260c08201528260e0820152826101008201528261012082015282610140820152015260043560005260cc602052610180604060002060ff60405191610e5883613498565b54610e6582821684613b16565b818160081c1615156020840152818160101c1615156040840152818160181c161515606084015262ffffff8160201c16608084015263ffffffff8160381c1660a084015262ffffff8160581c1660c084015261ffff8160701c1660e084015261ffff8160801c16610100840152818160901c16610120840152818160981c1661014084015260a01c16151561016082015261016060405191610f08838251613581565b60208101511515602084015260408101511515604084015260608101511515606084015262ffffff608082015116608084015263ffffffff60a08201511660a084015262ffffff60c08201511660c084015261ffff60e08201511660e084015261ffff6101008201511661010084015260ff6101208201511661012084015260ff6101408201511661014084015201511515610160820152f35b3461032d5760208060031936011261032d57610fbc6133f7565b906000549160ff8360081c16159081809261133f575b8015611328575b156112fe57600193828560ff198316176000556112ec575b5060005460ff8160081c16156112c25775ffffffffffffffffffffffffffffffffffffffff00001975ffffffffffffffffffffffffffffffffffffffff000060ff9360101b169116178060005560081c16156112c257611050336158ad565b620151808042049080820291808304821490151715610ab657620545ff19828101928311610ab65760cb92835469ffffffffff0000000000602892831b169064ffffffffff936203f480858469ffffffffff000000000019851617861c160190858211610ab6574201428111610ab657790927c00000000000000000000000000000000000000000000000937fffffffffffff000000ffffffffffffffff0000000000000000000000000000006effffffffff0000000000000000000061113161112c6111278b62093a8081989e9c9e04166136de565b6136ae565b6136c6565b60501b1694161791161717178455600090600219430192438411925b600381106111ea575050505050506000805260ca83526040600020547fffffffffffffffffff0000000000000000ffffffffffffffffffffffffffffff76ffffffffffffffff00000000000000000000000000000083549260781b1691161790556111b457005b7f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989161ff001960005416600055604051908152a1005b60c890808201809211610ab65761120082613706565b828854881c16848202828104861483151715610ab65761121f916136f9565b848101809111610ab65760608b7f643b454d39972ed209afefa4a771c7a9057229bc7e6b66566f5be8441bf9b1e2928e604051928784528301526040820152a16040519161126c8361350b565b8b8352858b3681860137610ab6578b926112bc917f3632d8eba811d69784e6904a58de6e0ab55f32638189623b309895beaa6920c46112ab858b6136f9565b40186112b683613742565b52613c27565b0161114d565b60046040517fd7e6bcf8000000000000000000000000000000000000000000000000000000008152fd5b61ffff19166101011760005584610ff1565b60046040517f0dc149f0000000000000000000000000000000000000000000000000000000008152fd5b50303b158015610fd95750600160ff851614610fd9565b50600160ff851610610fd2565b3461032d57602036600319011261032d5760043560005260ca6020526020604060002054604051908152f35b3461032d57604036600319011261032d5767ffffffffffffffff60243581811161032d573660238201121561032d578060040135918211610d94578160051b90604051916020936113cb85830185613543565b83526024848401918301019136831161032d57602401905b82821061143657836001600160a01b0360005460101c16330361140c5761073b90600435613c27565b60046040517f580ae425000000000000000000000000000000000000000000000000000000008152fd5b813581529084019084016113e3565b3461032d57602036600319011261032d5760043560005260cc602052602060ff604060002054166114796040518092613581565bf35b3461032d576114893661340d565b61149493919361586f565b7fa3ae391b4ec3b8276739f8c31c7074ec8a45be9b7f9663574f58fa257b49a060604051806114c7848888888c86614a69565b0390a182810361194957821561191f5760005b8181106114e357005b6114f561027861ffff83168686614cfb565b61ffff6115058184168589614d0b565b911680156118f55761ffff881660005260d060205260406000209060005260205260ff6040600020541660288110156108b9576118cb577343da95dc00babae5d00ebea2c8088f3f7cd778323b1561032d5760006115779160405180938192632ae2d1eb60e01b835260048301614d2e565b03817343da95dc00babae5d00ebea2c8088f3f7cd778325af48015610a73576118bc575b506115b36115ae61ffff83168488614d0b565b614fb1565b9061ffff871660005260d0602052604060002061ffff6115d96102788285168989614cfb565b1660005260205260406000209180519260288410156108b95761160466ffff000000000094826142dd565b6020820151815464ffffffff00191660089190911b64ffffffff001617815563ffffffff916040810151825469ffffff00000000000000606084015160381b169169ffffffffff00000000001997889160281b1691161717825562ffffff608061168c828285015116859062ffffff60501b82549160501b169062ffffff60501b1916179055565b60a0830151845460c08086015160e087015171ffffffffff0000000000000000000000000019909316606894851b6effff00000000000000000000000000161760789190911b60ff60781b161760809290921b61ffff60801b169190911786559094600191610100860151825460ff60901b191660909190911b60ff60901b16178255856101208101519183549060ff60a81b61014084015160a81b169060ff60c01b61ffff60b01b61016086015160b01b1691610180860151901b1660ff60c81b6101a086015160c81b169161ffff60d01b6101c087015160d01b169361ffff60e01b6101e088015160e01b169572ffffffffffffffffffffffffffffffffffffff61ffff60981b6001600160f81b031961022060ff60f01b6102008d015160081c169b0151169a60981b169116171717171717171717815501946102408401519060288210156108b9576117e561180692886142dd565b610260850151875464ffffffff001916911660081b64ffffffff0016178655565b6102808301519060288210156108b95761189472ffffffffffff0000000000000000000000000019936fffffff000000000000000000000000009360019a89549065ff000000000069ffffffff0000000000006102a08b015160301b169360281b169116171788556102c086015116879062ffffff60501b82549160501b169062ffffff60501b1916179055565b62ffffff60801b6102e0850151916103008854960151901b16941b16911617179055016114da565b6118c590613484565b8661159b565b60046040517fa7f589fe000000000000000000000000000000000000000000000000000000008152fd5b60046040517f665991b7000000000000000000000000000000000000000000000000000000008152fd5b60046040517f96ac6b94000000000000000000000000000000000000000000000000000000008152fd5b60046040517fff633a38000000000000000000000000000000000000000000000000000000008152fd5b3461032d57606036600319011261032d5767ffffffffffffffff60043581811161032d576119a59036906004016133c6565b60243583811161032d576119bd9036906004016133c6565b92909360443590811161032d576119d89036906004016133c6565b9190926119e361586f565b82810361194957801561191f5760005b8181106119fc57005b61ffff8116611a0f610278828587614cfb565b90611a28611a1e828a8c6157a6565b919092888a6157a6565b611a3393919361586f565b7fa3ae391b4ec3b8276739f8c31c7074ec8a45be9b7f9663574f58fa257b49a06060405180611a66848888888c86614a69565b0390a182810361194957821561191f5760005b818110611a8e575050505050506001016119f3565b611aa061027861ffff83168686614cfb565b611aaf61ffff83168488614d0b565b9061ffff8116156118f55761ffff881660005260d060205261ffff6040600020911660005260205260ff6040600020541660288110156108b9576118cb577343da95dc00babae5d00ebea2c8088f3f7cd778323b1561032d576000611b289160405180938192632ae2d1eb60e01b835260048301614d2e565b03817343da95dc00babae5d00ebea2c8088f3f7cd778325af48015610a7357611e47575b50611b5f6115ae61ffff83168488614d0b565b9061ffff871660005260d0602052604060002061ffff611b856102788285168989614cfb565b1660005260205260406000209180519260288410156108b957611bb066ffff000000000094826142dd565b6020820151815464ffffffff00191660089190911b64ffffffff001617815563ffffffff916040810151825469ffffff00000000000000606084015160381b169169ffffffffff00000000001997889160281b1691161717825562ffffff6080611c38828285015116859062ffffff60501b82549160501b169062ffffff60501b1916179055565b60a0830151845460c08086015160e087015171ffffffffff0000000000000000000000000019909316606894851b6effff00000000000000000000000000161760789190911b60ff60781b161760809290921b61ffff60801b169190911786559094600191610100860151825460ff60901b191660909190911b60ff60901b16178255856101208101519183549060ff60a81b61014084015160a81b169060ff60c01b61ffff60b01b61016086015160b01b1691610180860151901b1660ff60c81b6101a086015160c81b169161ffff60d01b6101c087015160d01b169361ffff60e01b6101e088015160e01b169572ffffffffffffffffffffffffffffffffffffff61ffff60981b6001600160f81b031961022060ff60f01b6102008d015160081c169b0151169a60981b169116171717171717171717815501946102408401519060288210156108b9576117e5611d9192886142dd565b6102808301519060288210156108b957611e1f72ffffffffffff0000000000000000000000000019936fffffff000000000000000000000000009360019a89549065ff000000000069ffffffff0000000000006102a08b015160301b169360281b169116171788556102c086015116879062ffffff60501b82549160501b169062ffffff60501b1916179055565b62ffffff60801b6102e0850151916103008854960151901b16941b1691161717905501611a79565b611e5090613484565b8d611b4c565b3461032d57611e70611e673661358e565b929190916137c5565b6040805161ffff93909316835262ffffff91909116602083015290f35b3461032d57611e9b3661337f565b9060005260d46020526040600020805482101561032d57610c6e91610c4891613639565b3461032d57600036600319011261032d5760206001600160a01b0360975416604051908152f35b3461032d57602036600319011261032d57600435611f0261586f565b622dc6c08111611f5b577fffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffff79ffffff000000000000000000000000000000000000000000000060cb549260b81b1691161760cb55600080f35b60046040517fbfbc293b000000000000000000000000000000000000000000000000000000008152fd5b3461032d57611f933661337f565b620545ff194201428111610ab65762093a80809104818102918183041490151715610ab657620546008101809111610ab65762015180928342049284840293808504861490151715610ab657604094611ff361200b9462ffffff966136a1565b049067ffffffffffffffff60cb5460781c16926137c5565b61ffff849392935193168352166020820152f35b3461032d57602036600319011261032d5760043560c95481101561032d576120486020916135ec565b90546040519160031b1c8152f35b3461032d57602036600319011261032d5761206f6139b4565b5060043560005260d260205261024061208b6040600020613a38565b611479604051809261ffff8082511683528060208301511660208401528060408301511660408401528060608301511660608401528060808301511660808401528060a08301511660a08401528060c08301511660c08401528060e08301511660e084015261010060ff818401511690840152610120818184015116908401526101408181840151169084015261016060ff818401511690840152610180818184015116908401526101a0818184015116908401526101c060ff8184015116908401526101e0818184015116908401526102009081830151169083015260ff6102208092015116910152565b3461032d57602036600319011261032d5760043560005260cc6020526101806040600020546040519060ff906121af83838316613581565b818160081c1615156020840152818160101c1615156040840152818160181c161515606084015262ffffff808260201c16608085015263ffffffff8260381c1660a08501528160581c1660c084015261ffff808260701c1660e08501528160801c16610100840152818160901c16610120840152818160981c1661014084015260a01c161515610160820152f35b3461032d57602036600319011261032d5761ffff612259613395565b1660005260cc602052602062ffffff60406000205460581c16604051908152f35b3461032d576122883661358e565b9092909190601081116122d7575090826122ad926122a8610c6e956138dd565b613bf7565b604051906020820152602081526122c38161350b565b6040519182916020835260208301906135ac565b9091906040106123a5576122ea8361392a565b9260005b6004811061233e57505050506040519060208083016000905b600482106123295750505050806080610c6e925261232481613527565b6122c3565b82806001928651815201940191019092612307565b806123578484876123516001968b613919565b51613bf7565b6123618288613919565b528061236e575b016122ee565b6123788187613919565b51865118604051602080820192835281526123928161350b565b51902061239f8288613919565b52612368565b634e487b7160e01b600052600160045260246000fd5b3461032d57600036600319011261032d57602060405160038152f35b3461032d57604036600319011261032d576123f0613395565b61ffff806123fc6133a6565b16918215612437571660005260d0602052604060002090600052602052602062ffffff60406000205460501c165b62ffffff60405191168152f35b9091501660005260cc602052602062ffffff604060002054821c1661242a565b3461032d57600036600319011261032d5761247061586f565b60006001600160a01b036097546001600160a01b03198116609755167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a3005b3461032d57600036600319011261032d5760207fffffffffffffffff00000000000000000000000000000000000000000000000060cb5460481b16604051908152f35b3461032d57600036600319011261032d576020604051620151808152f35b3461032d5760208060031936011261032d5760043567ffffffffffffffff811161032d576125459036906004016133c6565b9061254e61586f565b60005b828110612589576040517fb7bd806d66ef5249b63740995dc2366b90a3e2b78344eb5c0d573daa91971c68908061081d868683613f74565b61ffff61259a610278838686613eb2565b1660005260cc845260ff6040600020541660288110156108b957156125d557806102ae6125cb6125d0938686613eb2565b614358565b612551565b60046040517fdbab6626000000000000000000000000000000000000000000000000000000008152fd5b3461032d57602036600319011261032d5761ffff61261b613395565b6126236139b4565b501660005260d26020526102a0604060002060cc60205260ff61264b60406000205492613a38565b91612738604051809461ffff8082511683528060208301511660208401528060408301511660408401528060608301511660608401528060808301511660808401528060a08301511660a08401528060c08301511660c08401528060e08301511660e084015261010060ff818401511690840152610120818184015116908401526101408181840151169084015261016060ff818401511690840152610180818184015116908401526101a0818184015116908401526101c060ff8184015116908401526101e0818184015116908401526102009081830151169083015260ff6102208092015116910152565b6127486102408401838316613581565b62ffffff8160581c1661026084015260981c16610280820152f35b3461032d57600036600319011261032d576001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001630036127ce5760206040517f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc8152f35b60046040517f7251afea000000000000000000000000000000000000000000000000000000008152fd5b604036600319011261032d5761280c6133f7565b60243567ffffffffffffffff811161032d573660238201121561032d5780600401359061283882613565565b6128456040519182613543565b82815260209283820192366024838301011161032d578160009260248793018637830101526001600160a01b03807f00000000000000000000000000000000000000000000000000000000000000001690813014612ae0577f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc918183541603612ab6576128d061586f565b7f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd91435460ff161561290857505050505061073b906158f5565b8516906040516352d1902d60e01b81528581600481865afa60009181612a87575b5061293f57600460405163081007d160e41b8152fd5b03612a5d5761294d856158f5565b604051907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b600080a2815115801590612a55575b61298757005b843b15612a2d575061073b93600092839251915af43d15612a25573d906129ad82613565565b916129bb6040519384613543565b82523d60008484013e5b7f416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c604051936129f3856134ef565b602785528401527f206661696c6564000000000000000000000000000000000000000000000000006040840152615962565b6060906129c5565b807f1fdb1d6d0000000000000000000000000000000000000000000000000000000060049252fd5b506001612981565b60046040517f8ae7e94c000000000000000000000000000000000000000000000000000000008152fd5b9091508681813d8311612aaf575b612a9f8183613543565b8101031261032d57519088612929565b503d612a95565b60046040517f36a15c6e000000000000000000000000000000000000000000000000000000008152fd5b60046040517f0ce7e818000000000000000000000000000000000000000000000000000000008152fd5b3461032d57612b183661340d565b909391612b2361586f565b801561191f578181036119495760005b818110612b6e5750907fbb9be5d1d0efdcb294acb14cca55a27436b316199041eb8cef7cac3d121a14c89461081d9260405195869586614a69565b612b8061027861ffff83168488614cfb565b612b8f61ffff83168589614d0b565b9061ffff861660005260d060205261ffff6040600020911660005260205260ff6040600020541660288110156108b95715612f2d577343da95dc00babae5d00ebea2c8088f3f7cd778323b1561032d576000612bff9160405180938192632ae2d1eb60e01b835260048301614d2e565b03817343da95dc00babae5d00ebea2c8088f3f7cd778325af48015610a7357612f1e575b50612c366115ae61ffff83168589614d0b565b9061ffff851660005260d0602052604060002061ffff612c5c610278828516878b614cfb565b1660005260205260406000209180519260288410156108b957612c8766ffff000000000094826142dd565b6020820151815464ffffffff00191660089190911b64ffffffff001617815563ffffffff916040810151825469ffffff00000000000000606084015160381b169169ffffffffff00000000001997889160281b1691161717825562ffffff6080612d0f828285015116859062ffffff60501b82549160501b169062ffffff60501b1916179055565b60a0830151845460c08086015160e087015171ffffffffff0000000000000000000000000019909316606894851b6effff00000000000000000000000000161760789190911b60ff60781b161760809290921b61ffff60801b169190911786559094600191610100860151825460ff60901b191660909190911b60ff60901b16178255856101208101519183549060ff60a81b61014084015160a81b169060ff60c01b61ffff60b01b61016086015160b01b1691610180860151901b1660ff60c81b6101a086015160c81b169161ffff60d01b6101c087015160d01b169361ffff60e01b6101e088015160e01b169572ffffffffffffffffffffffffffffffffffffff61ffff60981b6001600160f81b031961022060ff60f01b6102008d015160081c169b0151169a60981b169116171717171717171717815501946102408401519060288210156108b9576117e5612e6892886142dd565b6102808301519060288210156108b957612ef672ffffffffffff0000000000000000000000000019936fffffff000000000000000000000000009360019a89549065ff000000000069ffffffff0000000000006102a08b015160301b169360281b169116171788556102c086015116879062ffffff60501b82549160501b169062ffffff60501b1916179055565b62ffffff60801b6102e0850151916103008854960151901b16941b1691161717905501612b33565b612f2790613484565b86612c23565b60046040517f510fec52000000000000000000000000000000000000000000000000000000008152fd5b3461032d5760208060031936011261032d5760e09061ffff612f77613395565b600060c0604051612f8781613468565b82815282868201528260408201528260608201528260808201528260a082015201521660005260d18152604060002060405190612fc382613468565b5460019181830b93848252808201908360101c850b82526040830184821c860b815260608401918560301c870b835260808501938660401c880b855260c060a08701968860501c8a0b8852019660601c880b875260405198895251870b9088015251850b604087015251840b606086015251830b608085015251820b60a084015251900b60c0820152f35b3461032d57602036600319011261032d5761ffff61306a613395565b1660005260cc6020526040806000205463ffffffff82519160ff8160901c16835260381c166020820152f35b3461032d5760208060031936011261032d576130b06133f7565b906001600160a01b03807f000000000000000000000000000000000000000000000000000000000000000016803014612ae0577f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc908282541603612ab65761311661586f565b604051908382019282841067ffffffffffffffff851117610d9457836040526000835260ff7f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143541660001461317357505050505061073b906158f5565b8516906040516352d1902d60e01b81528581600481865afa600091816131f9575b506131aa57600460405163081007d160e41b8152fd5b03612a5d576131b8856158f5565b604051907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b600080a28151158015906131f15761298757005b506000612981565b9091508681813d8311613221575b6132118183613543565b8101031261032d57519088613194565b503d613207565b3461032d57602036600319011261032d576004356001600160a01b03811680910361032d5761325561586f565b6001600160a01b031960d354161760d355600080f35b3461032d57604036600319011261032d57613284613395565b60243567ffffffffffffffff811161032d576132a49036906004016133c6565b90916132ae61586f565b811561191f5761ffff9081169060005b83811061330557505061081d7f32fe84254806f7c0fd6cbd970048ace22c87c23fb04b33e52b3115d7ff485a5a9360405193849384526040602085015260408401916149f3565b60019083600052602060d08152604060002090846133296102788286168a8c614cfb565b1660005252600082604082208281550155016132be565b3461032d57611e706133513661337f565b9061374f565b3461032d57602036600319011261032d576020613375600435613863565b1515604051908152f35b604090600319011261032d576004359060243590565b6004359061ffff8216820361032d57565b6024359061ffff8216820361032d57565b359061ffff8216820361032d57565b9181601f8401121561032d5782359167ffffffffffffffff831161032d576020808501948460051b01011161032d57565b600435906001600160a01b038216820361032d57565b90606060031983011261032d5760043561ffff8116810361032d579167ffffffffffffffff9160243583811161032d578261344a916004016133c6565b9390939260443591821161032d57613464916004016133c6565b9091565b60e0810190811067ffffffffffffffff821117610d9457604052565b67ffffffffffffffff8111610d9457604052565b610180810190811067ffffffffffffffff821117610d9457604052565b610240810190811067ffffffffffffffff821117610d9457604052565b610320810190811067ffffffffffffffff821117610d9457604052565b6060810190811067ffffffffffffffff821117610d9457604052565b6040810190811067ffffffffffffffff821117610d9457604052565b60a0810190811067ffffffffffffffff821117610d9457604052565b90601f8019910116810190811067ffffffffffffffff821117610d9457604052565b67ffffffffffffffff8111610d9457601f01601f191660200190565b9060288210156108b95752565b608090600319011261032d5760043590602435906044359060643590565b919082519283825260005b8481106135d8575050826000602080949584010152601f8019910116010190565b6020818301810151848301820152016135b7565b60c9548110156136235760c96000527f66be4f155c5ef2ebd3772b228f2f00681e4ed5826cdb3b1943cc11ad15ad1d280190600090565b634e487b7160e01b600052603260045260246000fd5b80548210156136235760005260206000200190600090565b604060031982011261032d576004359160243567ffffffffffffffff9283821161032d578060238301121561032d57816004013593841161032d5760248460061b8301011161032d576024019190565b91908203918211610ab657565b906205460064ffffffffff80931601918211610ab657565b9062093a8064ffffffffff80931601918211610ab657565b9062093a8064ffffffffff80931602918216918203610ab657565b91908201809211610ab657565b60c95468010000000000000000811015610d945780600161372a920160c9556135ec565b819291549060031b91821b91600019901b1916179055565b8051156136235760200190565b61379e6137b19267ffffffffffffffff60cb5460781c168360005260d5602052604060002054916040519060208201928352604082015260408152613793816134ef565b51902060381c613bd7565b9060005260d56020526040600020613639565b50549062ffffff61ffff83169260101c1690565b9193929360009483865260d460205260408620549260405190602082019283526040820152604081526137f7816134ef565b519020908060031b908082046008149015171561382f576040926137b1959692613821921c613bd7565b92815260d460205220613639565b602486634e487b7160e01b81526011600452fd5b6000198114610ab65760010190565b9060088110156136235760051b0190565b61386c906138ae565b6000811280156138a2575b61389c57613884906135ec565b90549060031b1c60005260ca60205260406000205490565b50600090565b508060c9541115613877565b64ffffffffff60cb5460281c16908181106138d55762015180916138d1916136a1565b0490565b505060001990565b6138e690613863565b9081156138ef57565b60046040517fb4190460000000000000000000000000000000000000000000000000000000008152fd5b9060048110156136235760051b0190565b6040516080810181811067ffffffffffffffff821117610d945760405260803682378091600090815b6004808210156139ac576201518090818302918383041483151715613999575090613988613983600193856136a1565b6138dd565b6139928287613919565b5201613953565b846011602492634e487b7160e01b835252fd5b505050505090565b604051906139c1826134b5565b816102206000918281528260208201528260408201528260608201528260808201528260a08201528260c08201528260e08201528261010082015282610120820152826101408201528261016082015282610180820152826101a0820152826101c0820152826101e0820152826102008201520152565b90604051613a45816134b5565b61022081935461ffff8082168452808260101c166020850152808260201c166040850152808260301c166060850152808260401c166080850152808260501c1660a0850152808260601c1660c0850152808260701c1660e085015260ff8260801c16610100850152808260881c16610120850152808260981c1661014085015260ff8260a81c16610160850152808260b01c16610180850152808260c01c166101a085015260ff8260d01c166101c0850152808260d81c166101e08501528160e81c1661020084015260f81c910152565b60288210156108b95752565b60405190613b2f826134d2565b816103006000918281528260208201528260408201528260608201528260808201528260a08201528260c08201528260e08201528261010082015282610120820152826101408201528261016082015282610180820152826101a0820152826101c0820152826101e08201528261020082015282610220820152826102408201528261026082015282610280820152826102a0820152826102c0820152826102e08201520152565b8115613be1570690565b634e487b7160e01b600052601260045260246000fd5b929091604051926020840194855260408401526060830152608082015260808152613c2181613527565b51902090565b9060009082825260ca60205260409081832054613e89576001815103613e6057613c5090613742565b51928315613e37575b80835260ca60205283828420556001600160a01b038060d3541680613de7575b5060d6541680613d86575b50907f5c69e7026b653d8606b5613bb00fd8c4b0504b1cbe8db600c406faac180924d5918151908152846020820152a160cb54906201518090814204828102928184041490151715613d725764ffffffffff91828460501c161115613cea575b50505050565b620545ff19420190428211613d7257506effffffffff00000000000000000000613d5961112c6111277fffffffffffffffffff00000000000000000000000000ffffffffffffffffffff9562093a8076ffffffffffffffff0000000000000000000000000000009604166136de565b60501b169360781b169116171760cb5538808080613ce4565b80634e487b7160e01b602492526011600452fd5b803b15613de35783809160248551809481936327fe556d60e21b83528a60048401525af18015613dd657908491613dbe575b50613c84565b613dc790613484565b613dd2578238613db8565b8280fd5b50505051903d90823e3d90fd5b8380fd5b803b15613e335784809160248651809481936327fe556d60e21b83528b60048401525af18015613e295715613c7957613e2290949194613484565b9238613c79565b84513d87823e3d90fd5b8480fd5b92506000194301438111613e4c574092613c59565b602483634e487b7160e01b81526011600452fd5b600482517fff633a38000000000000000000000000000000000000000000000000000000008152fd5b600482517f533d99dd000000000000000000000000000000000000000000000000000000008152fd5b91908110156136235760051b810135906102be198136030182121561032d570190565b3590811515820361032d57565b359062ffffff8216820361032d57565b359063ffffffff8216820361032d57565b359060ff8216820361032d57565b602090613f2f8261ffff9283613f26826133b7565b168652016133b7565b16910152565b60ff613f2f6040809361ffff80613f4b836133b7565b168752613f5a602083016133b7565b16602087015201613f03565b35908160010b820361032d57565b91602090808285018386525260409182850194838360051b82010195856000925b858410613fa757505050505050505090565b9091929394959697603f1982820301845288356102be198436030181121561032d576102c09190840161ffff83830181613fe0846133b7565b16845289830135602881101561032d57613ffd908b860190613581565b6140088c8401613ed5565b15158c85015260609161401c838501613ed5565b151583860152608061402f818601613ed5565b15159086015262ffffff60a081614047828801613ee2565b169087015260c063ffffffff61405e828801613ef2565b169087015260e090614071828701613ee2565b1690860152610100816140858287016133b7565b1690860152610120906140998286016133b7565b169085015260ff610140816140af828701613f03565b1690860152610160906140c3828601613f03565b16908501526101806140d6818501613ed5565b15159085015236839003601e19016101a0848101358281121561032d578501908c823592019367ffffffffffffffff9889841161032d578360061b3603861361032d578392890152528d6102e0870193916000915b81831061424e57505050506101c090818501359081121561032d578401918b8335930196831161032d578383023603871361032d5780869594928d97889303908701528381520195916000915b81831061422757505050509282916001946101e0614197818301613f66565b870b90830152856102006141ac838201613f66565b820b908401526102206141c0818401613f66565b820b908401526102406141d4818401613f66565b820b908401526102606141e8818401613f66565b820b908401526102806141fc818401613f66565b820b908401526142106102a0809301613f66565b900b9101529a019401940192969594939190613f95565b808093959697508861423d869a60019597613f35565b019701930190918b95949392614178565b808661425f86986001959697613f11565b0195019201908f61412b565b35801515810361032d5790565b3561ffff8116810361032d5790565b3562ffffff8116810361032d5790565b903590601e198136030182121561032d570180359067ffffffffffffffff821161032d57602001918160061b3603831361032d57565b91908110156136235760061b0190565b9060288110156108b95760ff80198354169116179055565b3563ffffffff8116810361032d5790565b3560ff8116810361032d5790565b903590601e198136030182121561032d570180359067ffffffffffffffff821161032d5760200191606082023603831361032d57565b358060010b810361032d5790565b61436181614278565b61ffff916000918316156149c95761010081019161437e83614278565b610120830190858061438f84614278565b1691161161499f5760e083019162ffffff806143aa85614287565b161561493d576143b984614287565b168015614929576236ee80066148ff575b856143d485614278565b16815260209460cc865260409283832087870135916028831015613e33576143fc83836142dd565b61440788870161426b565b15158254946060988a8c8b820161441d9061426b565b1515608083019961442d8b61426b565b151560181b63ff000000169260a0850161444690614287565b901b66ffffff00000000169360c00161445e906142f5565b60381b6affffffff00000000000000169461447890614287565b60581b6dffffff0000000000000000000000169561449590614278565b60701b6fffff0000000000000000000000000000169660081b61ff0016907fffffffffffffffffffffffffffffffff000000000000000000000000000000ff16179060101b62ff00001617171717171782556144f090614278565b81547fffffffffffffffffffffffffffff0000ffffffffffffffffffffffffffffffff1660809190911b61ffff60801b161781556145316101408801614306565b815460ff60901b191660909190911b60ff60901b161781556145566101608801614306565b81546145656101808a0161426b565b151560a01b74ff0000000000000000000000000000000000000000169160981b73ff0000000000000000000000000000000000000016907fffffffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffff1617179055876145cc87614278565b16835260d28752838320886145e088614278565b16845283858120557343da95dc00babae5d00ebea2c8088f3f7cd77832916101a088019161460e838a614297565b90853b156148fb579087895180937f1a2bbf3d00000000000000000000000000000000000000000000000000000000825283604483018d600485015252606482019093835b8d8282106148d857505050819293508560248301520381885af480156148ce576148bb575b506101c0890193614689858b614314565b92823b156148b75791899189938c8685519788967f91f221eb000000000000000000000000000000000000000000000000000000008852604488019060048901525260648601939187905b82821061488d575050505083918291602483015203915af480156148835790869161486f575b50506001036147f45750505081908661471286614278565b16815260d1865220946147286101e0850161434a565b94865461020086016147399061434a565b60101b9161474a610220880161434a565b901b9261475a610240880161434a565b60301b9461476b610260890161434a565b901b9561477b610280890161434a565b60501b976102a00161478c9061434a565b901b6dffff000000000000000000000000169716906dffffffffffffffffffffffffffff1916179063ffff000016179065ffff0000000016179067ffff00000000000016179069ffff00000000000000001617906bffff000000000000000000001617179055565b91959650929650614815935061480b915085614297565b9050151593614314565b905082614865575b5081614855575b5061482c5750565b600490517fb28b6f38000000000000000000000000000000000000000000000000000000008152fd5b61485f915061426b565b38614824565b151591503861481d565b61487890613484565b613e335784386146fa565b87513d88823e3d90fd5b91948291949698508397506148a481600195613f35565b0195019101908694928c9694928f6146d4565b8880fd5b6148c790969196613484565b9438614678565b88513d89823e3d90fd5b919450925080826148eb60019488613f11565b0194019101928a92859294614653565b8780fd5b60046040517ffbf84394000000000000000000000000000000000000000000000000000000008152fd5b602482634e487b7160e01b81526012600452fd5b506101a0840161494d8186614297565b905061495a575b506143ca565b6149649085614297565b1561498b576149766020889201614278565b16801561492957618ca0066148ff5738614954565b602482634e487b7160e01b81526032600452fd5b60046040517f3ab272e6000000000000000000000000000000000000000000000000000000008152fd5b60046040517fc78a7d8b000000000000000000000000000000000000000000000000000000008152fd5b91908082526020809201929160005b828110614a10575050505090565b90919293828060019261ffff614a25896133b7565b16815201950193929101614a02565b9035601e198236030181121561032d57016020813591019167ffffffffffffffff821161032d578160051b3603831361032d57565b949192909461ffff8096168152614a8d6060946020938685850152868401916149f3565b906040908181840391015283825282820194838560051b84010197876000945b878610614ac1575050505050505050505090565b90919293949596979899601f19828203018a528a356101be198436030181121561032d57830190602882358181101561032d5791614b00818c94613581565b614b0b838501613f66565b91600192830b8483015262ffffff80614b258c8801613ee2565b168b84015280614b368b8801613ee2565b168a840152614b5e6080614b4c81890189614a34565b90916101c080918801528601916149f3565b60a09186614b6e848a018a614a34565b939094878203908801528381520192916000915b818310614cd4575050505060c089614b9b8289016133b7565b169084015260ff60e081614bb0828a01613f03565b169085015261010090614bc4828901613f03565b169084015261012089614bd88289016133b7565b169084015261014089614bec8289016133b7565b1690840152610160614bff818801613ed5565b1515908401526101809185614c1684890189614a34565b939094868203908701528381520192916000915b818310614ca357505050508390614c476101a09687810190614a34565b9390968183039101528281520193916000915b808310614c7d5750505050806001929c019a019601949392919097969597614aad565b919380849663ffffffff614c918597613ef2565b168152019501930190918b9392614c5a565b919390928095975035908282101561032d578f81614cc382938a95613581565b019501930190918e96949392614c2a565b9193978084979984614ce78b9597613ee2565b168152019601930190918f97959392614b82565b91908110156136235760051b0190565b91908110156136235760051b810135906101be198136030182121561032d570190565b60208082526101e0820190602884358181101561032d57614d559083869594960190613581565b614d60848601613f66565b92600193840b604082015262ffffff9586614d7d60408301613ee2565b16606083015286614d9060608301613ee2565b166080830152614da36080820182614a34565b806101c0999299968760a0870152526102008401989060005b818110614f5357505050614dd360a0830183614a34565b601f19858b03810160c0870152818b52998901926000905b828210614f2b5750505050614e7d614e6b61ffff80614e0c60c087016133b7565b1660e0870152614e5b81614e4b60ff614e3b81614e2b60e08c01613f03565b1661010090818d01528a01613f03565b1661012090818b015288016133b7565b16610140908189015286016133b7565b1661016090818701528401613ed5565b15156101809081860152830183614a34565b8483038a016101a086810191909152818452928901956000905b828210614efa575050505081614eb291889594930190614a34565b9490978284030191015282815201939260005b828110614ed457505050505090565b9091928280869763ffffffff614eea8599613ef2565b1681520196019493929101614ec5565b90919296879a98999a35908282101561032d578981614f1b82938f95613581565b9a9c9b9a01980193920190614e97565b90919293988a80829c9a9b84614f4089613ee2565b1681529a9c9b9a01950193920190614deb565b909199978980829b999a61ffff614f698f6133b7565b168152019b989a999801929101614dbc565b903590601e198136030182121561032d570180359067ffffffffffffffff821161032d57602001918160051b3603831361032d57565b614fb9613b22565b50614fc7610160820161426b565b6000901561579757506001600160f81b031960805b60f81b1680610200526001614ff5610180840184614f7b565b90501161576b575b5061500b60a0820182614f7b565b9050151580615742575b80156156fa575b8060a052156156ab575b60a05161567c575b60288135101561032d576150466101a0820182614f7b565b6000608052159050615677576150606101a0820182614f7b565b156136235761506e906142f5565b6080525b61507e6020820161434a565b60c05261508d60408201614287565b60e05261509c60608201614287565b906150aa6080820182614f7b565b600091501561567157506150c16080820182614f7b565b15613623576150cf90614278565b915b6150de60a0830183614f7b565b9050151580615667575b6000901561566157506150fe60a0830183614f7b565b156136235761510e60ff91614287565b16905b61511e6080840184614f7b565b600091506001101561565b57506151386080840184614f7b565b6001101561362357602061514c9101614278565b925b600161515d60a0830183614f7b565b90501180615651575b6000901561564b575061517c60a0820182614f7b565b6001101561362357615192602060ff9201614287565b16925b6151a26080830183614f7b565b600091506002101561564557506151bc6080830183614f7b565b600210156136235760406151d09101614278565b945b60026151e160a0850185614f7b565b9050118061563b575b60009015615635575061520060a0840184614f7b565b6002101561362357615216604060ff9201614287565b16935b61522560c08501614278565b9061523260e08601614306565b916152406101008701614306565b9461524e6101208801614278565b9761525c6101408901614278565b9a600161526d6101808b018b614f7b565b9050600061010052116000146156305761528b6101808a018a614f7b565b600110156136235760200135602881101561032d57610100525b60016152b56101a08b018b614f7b565b90506000610120521160001461562b576152d36101a08a018a614f7b565b600110156136235760206152e791016142f5565b610120525b60026152fc6101808b018b614f7b565b9050600061016052116000146156265761531a6101808a018a614f7b565b600210156136235760400135602881101561032d57610160525b60026153446101a08b018b614f7b565b905060006101405211600014615621576153626101a08a018a614f7b565b6002101561362357604061537691016142f5565b610140525b61538860a08a018a614f7b565b9050151580615618575b60006101805215615613576153aa60a08a018a614f7b565b15613623576153b890614287565b610180525b60016153cc60a08b018b614f7b565b9050118061560a575b60006101a05215615605576153ed60a08a018a614f7b565b600110156136235760206154019101614287565b6101a0525b600261541560a08b018b614f7b565b905011806155fc575b60006101c052156155d75761543660a08a018a614f7b565b600292919210156136235760ff61ffff9e9c8f829c9a819f849c9883869a9262ffffff829e61548c8a9661546d6040879f01614287565b6101c0525b615482604051806101e0526134d2565b356101e051613b16565b63ffffffff6080511660206101e051015260c05160010b60406101e05101528160e0511660606101e05101521660806101e05101521660a06101e05101521660c06101e05101521660e06101e0510152166101006101e0510152166101206101e0510152166101406101e0510152166101606101e0510152166101806101e0510152166101a06101e0510152166101c06101e0510152166101e0805101526001600160f81b031961020051166102006101e051015260006102206101e0510152615560610100516102406101e05101613b16565b63ffffffff61012051166102606101e0510152615587610160516102806101e05101613b16565b63ffffffff61014051166102a06101e051015262ffffff61018051166102c06101e051015262ffffff6101a051166102e06101e051015262ffffff6101c051166103006101e05101526101e05190565b61ffff9c9060ff8e9c8d829c9a83809c9883809c9862ffffff829a61548c869e615472565b5060a05161541e565b615406565b5060a0516153d5565b6153bd565b5060a051615392565b61537b565b615334565b6152ec565b6152a5565b93615219565b5060a051156151ea565b946151d2565b92615195565b5060a05115615166565b9261514e565b90615111565b5060a051156150e8565b916150d1565b615072565b7f200000000000000000000000000000000000000000000000000000000000000061020051176102005261502e565b60026156ba60a0830183614f7b565b905011806156cb575b60a052615026565b506156d960a0820182614f7b565b600210156136235762ffffff6156f3604060ff9301614287565b16116156c3565b50600161570a60a0830183614f7b565b905011801561501c575061572160a0820182614f7b565b600110156136235762ffffff61573b602060ff9301614287565b161161501c565b5061575060a0820182614f7b565b156136235762ffffff61576460ff92614287565b1611615015565b7f4000000000000000000000000000000000000000000000000000000000000000176102005238614ffd565b6001600160f81b031990614fdc565b90821015613623576134649160051b810190614f7b565b805490600090818155826157d057505050565b815260208120918201915b8281106157e757505050565b8181556001016157db565b805468010000000000000000811015610d945761581491600182018155613639565b9190916158595761ffff61582782614278565b1664ffffff000061584660208554948461ffff19871617875501614287565b60101b169164ffffffffff191617179055565b634e487b7160e01b600052600060045260246000fd5b6001600160a01b0360975416330361588357565b60046040517f6db2465f000000000000000000000000000000000000000000000000000000008152fd5b609754906001600160a01b0380911691826001600160a01b0319821617609755167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a3565b803b15615938576001600160a01b037f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc91166001600160a01b0319825416179055565b60046040517f71ab98ae000000000000000000000000000000000000000000000000000000008152fd5b9091901561596e575090565b81511561597e5750805190602001fd5b6159bc906040519182917f08c379a00000000000000000000000000000000000000000000000000000000083526020600484015260248301906135ac565b0390fdfea26469706673582212203a8c6106c01cc9fed6bfcfd415a98ad454ebc5441c507e78519a1853359a96d564736f6c63430008140033

Deployed Bytecode

0x610220604052600436101561001357600080fd5b60003560e01c80631929f7b31461335757806322793d2814613340578063264c73521461326b5780632dc918c2146132285780633659cfe61461309657806336f15ed71461304e5780634a2f04a114612f575780634ad8c52914612b0a5780634f1ef286146127f857806352d1902d14612763578063582e5452146125ff5780635f9e245e146125135780636528f09a146124f557806371315901146124b2578063715018a61461245757806374db3052146123d7578063770d0441146123bb5780637fe4cf6b1461227a57806381ab74511461223d57806383240f83146121775780638693ef18146120565780638796ba8c1461201f57806388b33c5b14611f855780638a54942f14611ee65780638da5cb5b14611ebf5780638eafc36414611e8d57806395016e4b14611e56578063b8987a6e14611973578063bbea74f41461147b578063bd880fae14611445578063be52e34f14611378578063beff730f1461134c578063c4d66de814610fa2578063cc3172a114610dd0578063cc76b91114610daa578063d42da17214610c72578063d623d54c14610c16578063dd56f38b14610b4d578063debde28414610b28578063e0c8628914610940578063e5df71fc146108f9578063e63e9b91146107aa578063e87df97214610767578063f2fde38b14610702578063f5a62e191461069f578063f691689c146103325763fb2bbc7f1461022257600080fd5b3461032d5761023036613651565b919061023a61586f565b60ff8311610303578160005260d590602082815261025b60406000206157bd565b60005b85811061026757005b61ffff61027d6102788389876142cd565b614278565b161580156102e2575b6102b8576102b390856000528483526102ae60406000206102a8838a886142cd565b906157f2565b613843565b61025e565b60046040517f28829e82000000000000000000000000000000000000000000000000000000008152fd5b5062ffffff6102fc836102f6848a886142cd565b01614287565b1615610286565b60046040517f2862b710000000000000000000000000000000000000000000000000000000008152fd5b600080fd5b3461032d57604036600319011261032d5761032061034e613395565b6103566133a6565b61ffff610361613b22565b921660005260d060205261ffff604060002091166000526020526040600020805461038f60ff821684613b16565b63ffffffff8160081c1660208401528060281c60010b604084015262ffffff8160381c16606084015262ffffff8160501c16608084015261ffff8160681c1660a084015260ff8160781c1660c084015261ffff8160801c1660e084015260ff8160901c1661010084015261ffff8160981c1661012084015260ff8160a81c1661014084015261ffff8160b01c1661016084015260ff8160c01c1661018084015260ff8160c81c166101a084015261ffff8160d01c166101c084015261ffff8160e01c166101e08401526001600160f81b03198160081b166102008401526001808260f61c161490811561068e575b50610618575b5060405190610493828251613581565b63ffffffff6020820151166020830152604081015160010b604083015262ffffff606082015116606083015262ffffff608082015116608083015261ffff60a08201511660a083015260ff60c08201511660c083015261ffff60e08201511660e083015260ff6101008201511661010083015261ffff6101208201511661012083015260ff6101408201511661014083015261ffff6101608201511661016083015260ff6101808201511661018083015260ff6101a0820151166101a083015261ffff6101c0820151166101c083015261ffff6101e0820151166101e08301526001600160f81b0319610200820151166102008301526102206001600160f81b03198183015116908301526105b16102408083015190840190613581565b61026063ffffffff8183015116908301526105d56102808083015190840190613581565b6102a063ffffffff8183015116908301526102c062ffffff8183015116908301526102e062ffffff81830151169083015262ffffff610300809201511690820152f35b600162ffffff91015461063260ff82166102408501613b16565b63ffffffff8160081c1661026084015261065660ff8260281c166102808501613b16565b63ffffffff8160301c166102a0840152818160501c166102c0840152818160681c166102e084015260801c1661030082015282610483565b60019150819060f51c16148461047d565b3461032d57602036600319011261032d576106b86133f7565b6106c061586f565b75ffffffffffffffffffffffffffffffffffffffff00001975ffffffffffffffffffffffffffffffffffffffff00006000549260101b16911617600055600080f35b3461032d57602036600319011261032d5761071b6133f7565b61072361586f565b6001600160a01b0381161561073d5761073b906158ad565b005b60046040517f7448fbae000000000000000000000000000000000000000000000000000000008152fd5b3461032d57602036600319011261032d576004356001600160a01b03811680910361032d5761079461586f565b6001600160a01b031960d654161760d655600080f35b3461032d5760208060031936011261032d5760043567ffffffffffffffff811161032d576107dc9036906004016133c6565b906107e561586f565b81805b610822576040517fe0c485464feab584463337a60a5f3b30eeae5d466aa5ce2d973b306518e576a6908061081d868683613f74565b0390a1005b6000190161ffff6108368183168585613eb2565b906108436060830161426b565b6108cf578061085183614278565b1660005260cc865260ff6040600020541660288110156108b95761087f575061087a8291614358565b6107e8565b61088a602492614278565b6040517fd44e9bef00000000000000000000000000000000000000000000000000000000815291166004820152fd5b634e487b7160e01b600052602160045260246000fd5b60046040517fccdd1ab5000000000000000000000000000000000000000000000000000000008152fd5b3461032d5760208060031936011261032d5761091660043561392a565b604051916000835b6004821061092b57608085f35b8280600192865181520194019101909261091e565b3461032d57600036600319011261032d5760c9548015159081610af6575b50610acc5760cb5464ffffffffff6201518081831601818111610ab6571690428211610a7f576000916001600160a01b03835460101c1662ffffff604051937f1b739ef10000000000000000000000000000000000000000000000000000000085526001600486015260b81c1660248401528260448160209687945af1918215610a7357600092610a43575b5060607f643b454d39972ed209afefa4a771c7a9057229bc7e6b66566f5be8441bf9b1e291610a1884613706565b8064ffffffffff1960cb54161760cb55604051908482526001868301526040820152a1604051908152f35b9091508281813d8311610a6c575b610a5b8183613543565b8101031261032d57519060606109ea565b503d610a51565b6040513d6000823e3d90fd5b604482604051907f1351c9400000000000000000000000000000000000000000000000000000000082524260048301526024820152fd5b634e487b7160e01b600052601160045260246000fd5b60046040517f974b4f8a000000000000000000000000000000000000000000000000000000008152fd5b600019810191508111610ab657610b0c906135ec565b90549060031b1c60005260ca602052604060002054158161095e565b3461032d57600036600319011261032d57602064ffffffffff60cb5416604051908152f35b3461032d57610b5b36613651565b9190610b6561586f565b60ff8311610303578160005260d4906020828152610b8660406000206157bd565b60005b858110610b9257005b61ffff610ba36102788389876142cd565b16158015610bfb575b8015610bda575b6102b857610bd590856000528483526102ae60406000206102a8838a886142cd565b610b89565b5062ffffff600a81610bf1856102f6868c8a6142cd565b1606161515610bb3565b5062ffffff610c0f836102f6848a886142cd565b1615610bac565b3461032d57610c243661337f565b9060005260d56020526040600020805482101561032d57610c6e91610c4891613639565b50546040805161ffff8316815260109290921c62ffffff16602083015290918291820190565b0390f35b3461032d57610c803661337f565b6040519167ffffffffffffffff61010080850182811186821017610d945760405260005b818110610d6657505060cb5460781c1660005b60078110610d225784610cca858561374f565b60e08301519262ffffff9384602093168382015261ffff8094169052604051938491906000925b60088410610cff5761020087f35b846040600192848387518b81511684520151168382015201930193019291610cf1565b8061ffff610d3584610d619488886137c5565b9190610d41848a613852565b519262ffffff6020610d53878d613852565b510191169052169052613843565b610cb7565b60405190604082019180831085841117610d9457602092604052600081526000838201528188015201610ca4565b634e487b7160e01b600052604160045260246000fd5b3461032d57602036600319011261032d576020610dc86004356138dd565b604051908152f35b3461032d57602036600319011261032d576000610160604051610df281613498565b8281528260208201528260408201528260608201528260808201528260a08201528260c08201528260e0820152826101008201528261012082015282610140820152015260043560005260cc602052610180604060002060ff60405191610e5883613498565b54610e6582821684613b16565b818160081c1615156020840152818160101c1615156040840152818160181c161515606084015262ffffff8160201c16608084015263ffffffff8160381c1660a084015262ffffff8160581c1660c084015261ffff8160701c1660e084015261ffff8160801c16610100840152818160901c16610120840152818160981c1661014084015260a01c16151561016082015261016060405191610f08838251613581565b60208101511515602084015260408101511515604084015260608101511515606084015262ffffff608082015116608084015263ffffffff60a08201511660a084015262ffffff60c08201511660c084015261ffff60e08201511660e084015261ffff6101008201511661010084015260ff6101208201511661012084015260ff6101408201511661014084015201511515610160820152f35b3461032d5760208060031936011261032d57610fbc6133f7565b906000549160ff8360081c16159081809261133f575b8015611328575b156112fe57600193828560ff198316176000556112ec575b5060005460ff8160081c16156112c25775ffffffffffffffffffffffffffffffffffffffff00001975ffffffffffffffffffffffffffffffffffffffff000060ff9360101b169116178060005560081c16156112c257611050336158ad565b620151808042049080820291808304821490151715610ab657620545ff19828101928311610ab65760cb92835469ffffffffff0000000000602892831b169064ffffffffff936203f480858469ffffffffff000000000019851617861c160190858211610ab6574201428111610ab657790927c00000000000000000000000000000000000000000000000937fffffffffffff000000ffffffffffffffff0000000000000000000000000000006effffffffff0000000000000000000061113161112c6111278b62093a8081989e9c9e04166136de565b6136ae565b6136c6565b60501b1694161791161717178455600090600219430192438411925b600381106111ea575050505050506000805260ca83526040600020547fffffffffffffffffff0000000000000000ffffffffffffffffffffffffffffff76ffffffffffffffff00000000000000000000000000000083549260781b1691161790556111b457005b7f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989161ff001960005416600055604051908152a1005b60c890808201809211610ab65761120082613706565b828854881c16848202828104861483151715610ab65761121f916136f9565b848101809111610ab65760608b7f643b454d39972ed209afefa4a771c7a9057229bc7e6b66566f5be8441bf9b1e2928e604051928784528301526040820152a16040519161126c8361350b565b8b8352858b3681860137610ab6578b926112bc917f3632d8eba811d69784e6904a58de6e0ab55f32638189623b309895beaa6920c46112ab858b6136f9565b40186112b683613742565b52613c27565b0161114d565b60046040517fd7e6bcf8000000000000000000000000000000000000000000000000000000008152fd5b61ffff19166101011760005584610ff1565b60046040517f0dc149f0000000000000000000000000000000000000000000000000000000008152fd5b50303b158015610fd95750600160ff851614610fd9565b50600160ff851610610fd2565b3461032d57602036600319011261032d5760043560005260ca6020526020604060002054604051908152f35b3461032d57604036600319011261032d5767ffffffffffffffff60243581811161032d573660238201121561032d578060040135918211610d94578160051b90604051916020936113cb85830185613543565b83526024848401918301019136831161032d57602401905b82821061143657836001600160a01b0360005460101c16330361140c5761073b90600435613c27565b60046040517f580ae425000000000000000000000000000000000000000000000000000000008152fd5b813581529084019084016113e3565b3461032d57602036600319011261032d5760043560005260cc602052602060ff604060002054166114796040518092613581565bf35b3461032d576114893661340d565b61149493919361586f565b7fa3ae391b4ec3b8276739f8c31c7074ec8a45be9b7f9663574f58fa257b49a060604051806114c7848888888c86614a69565b0390a182810361194957821561191f5760005b8181106114e357005b6114f561027861ffff83168686614cfb565b61ffff6115058184168589614d0b565b911680156118f55761ffff881660005260d060205260406000209060005260205260ff6040600020541660288110156108b9576118cb577343da95dc00babae5d00ebea2c8088f3f7cd778323b1561032d5760006115779160405180938192632ae2d1eb60e01b835260048301614d2e565b03817343da95dc00babae5d00ebea2c8088f3f7cd778325af48015610a73576118bc575b506115b36115ae61ffff83168488614d0b565b614fb1565b9061ffff871660005260d0602052604060002061ffff6115d96102788285168989614cfb565b1660005260205260406000209180519260288410156108b95761160466ffff000000000094826142dd565b6020820151815464ffffffff00191660089190911b64ffffffff001617815563ffffffff916040810151825469ffffff00000000000000606084015160381b169169ffffffffff00000000001997889160281b1691161717825562ffffff608061168c828285015116859062ffffff60501b82549160501b169062ffffff60501b1916179055565b60a0830151845460c08086015160e087015171ffffffffff0000000000000000000000000019909316606894851b6effff00000000000000000000000000161760789190911b60ff60781b161760809290921b61ffff60801b169190911786559094600191610100860151825460ff60901b191660909190911b60ff60901b16178255856101208101519183549060ff60a81b61014084015160a81b169060ff60c01b61ffff60b01b61016086015160b01b1691610180860151901b1660ff60c81b6101a086015160c81b169161ffff60d01b6101c087015160d01b169361ffff60e01b6101e088015160e01b169572ffffffffffffffffffffffffffffffffffffff61ffff60981b6001600160f81b031961022060ff60f01b6102008d015160081c169b0151169a60981b169116171717171717171717815501946102408401519060288210156108b9576117e561180692886142dd565b610260850151875464ffffffff001916911660081b64ffffffff0016178655565b6102808301519060288210156108b95761189472ffffffffffff0000000000000000000000000019936fffffff000000000000000000000000009360019a89549065ff000000000069ffffffff0000000000006102a08b015160301b169360281b169116171788556102c086015116879062ffffff60501b82549160501b169062ffffff60501b1916179055565b62ffffff60801b6102e0850151916103008854960151901b16941b16911617179055016114da565b6118c590613484565b8661159b565b60046040517fa7f589fe000000000000000000000000000000000000000000000000000000008152fd5b60046040517f665991b7000000000000000000000000000000000000000000000000000000008152fd5b60046040517f96ac6b94000000000000000000000000000000000000000000000000000000008152fd5b60046040517fff633a38000000000000000000000000000000000000000000000000000000008152fd5b3461032d57606036600319011261032d5767ffffffffffffffff60043581811161032d576119a59036906004016133c6565b60243583811161032d576119bd9036906004016133c6565b92909360443590811161032d576119d89036906004016133c6565b9190926119e361586f565b82810361194957801561191f5760005b8181106119fc57005b61ffff8116611a0f610278828587614cfb565b90611a28611a1e828a8c6157a6565b919092888a6157a6565b611a3393919361586f565b7fa3ae391b4ec3b8276739f8c31c7074ec8a45be9b7f9663574f58fa257b49a06060405180611a66848888888c86614a69565b0390a182810361194957821561191f5760005b818110611a8e575050505050506001016119f3565b611aa061027861ffff83168686614cfb565b611aaf61ffff83168488614d0b565b9061ffff8116156118f55761ffff881660005260d060205261ffff6040600020911660005260205260ff6040600020541660288110156108b9576118cb577343da95dc00babae5d00ebea2c8088f3f7cd778323b1561032d576000611b289160405180938192632ae2d1eb60e01b835260048301614d2e565b03817343da95dc00babae5d00ebea2c8088f3f7cd778325af48015610a7357611e47575b50611b5f6115ae61ffff83168488614d0b565b9061ffff871660005260d0602052604060002061ffff611b856102788285168989614cfb565b1660005260205260406000209180519260288410156108b957611bb066ffff000000000094826142dd565b6020820151815464ffffffff00191660089190911b64ffffffff001617815563ffffffff916040810151825469ffffff00000000000000606084015160381b169169ffffffffff00000000001997889160281b1691161717825562ffffff6080611c38828285015116859062ffffff60501b82549160501b169062ffffff60501b1916179055565b60a0830151845460c08086015160e087015171ffffffffff0000000000000000000000000019909316606894851b6effff00000000000000000000000000161760789190911b60ff60781b161760809290921b61ffff60801b169190911786559094600191610100860151825460ff60901b191660909190911b60ff60901b16178255856101208101519183549060ff60a81b61014084015160a81b169060ff60c01b61ffff60b01b61016086015160b01b1691610180860151901b1660ff60c81b6101a086015160c81b169161ffff60d01b6101c087015160d01b169361ffff60e01b6101e088015160e01b169572ffffffffffffffffffffffffffffffffffffff61ffff60981b6001600160f81b031961022060ff60f01b6102008d015160081c169b0151169a60981b169116171717171717171717815501946102408401519060288210156108b9576117e5611d9192886142dd565b6102808301519060288210156108b957611e1f72ffffffffffff0000000000000000000000000019936fffffff000000000000000000000000009360019a89549065ff000000000069ffffffff0000000000006102a08b015160301b169360281b169116171788556102c086015116879062ffffff60501b82549160501b169062ffffff60501b1916179055565b62ffffff60801b6102e0850151916103008854960151901b16941b1691161717905501611a79565b611e5090613484565b8d611b4c565b3461032d57611e70611e673661358e565b929190916137c5565b6040805161ffff93909316835262ffffff91909116602083015290f35b3461032d57611e9b3661337f565b9060005260d46020526040600020805482101561032d57610c6e91610c4891613639565b3461032d57600036600319011261032d5760206001600160a01b0360975416604051908152f35b3461032d57602036600319011261032d57600435611f0261586f565b622dc6c08111611f5b577fffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffff79ffffff000000000000000000000000000000000000000000000060cb549260b81b1691161760cb55600080f35b60046040517fbfbc293b000000000000000000000000000000000000000000000000000000008152fd5b3461032d57611f933661337f565b620545ff194201428111610ab65762093a80809104818102918183041490151715610ab657620546008101809111610ab65762015180928342049284840293808504861490151715610ab657604094611ff361200b9462ffffff966136a1565b049067ffffffffffffffff60cb5460781c16926137c5565b61ffff849392935193168352166020820152f35b3461032d57602036600319011261032d5760043560c95481101561032d576120486020916135ec565b90546040519160031b1c8152f35b3461032d57602036600319011261032d5761206f6139b4565b5060043560005260d260205261024061208b6040600020613a38565b611479604051809261ffff8082511683528060208301511660208401528060408301511660408401528060608301511660608401528060808301511660808401528060a08301511660a08401528060c08301511660c08401528060e08301511660e084015261010060ff818401511690840152610120818184015116908401526101408181840151169084015261016060ff818401511690840152610180818184015116908401526101a0818184015116908401526101c060ff8184015116908401526101e0818184015116908401526102009081830151169083015260ff6102208092015116910152565b3461032d57602036600319011261032d5760043560005260cc6020526101806040600020546040519060ff906121af83838316613581565b818160081c1615156020840152818160101c1615156040840152818160181c161515606084015262ffffff808260201c16608085015263ffffffff8260381c1660a08501528160581c1660c084015261ffff808260701c1660e08501528160801c16610100840152818160901c16610120840152818160981c1661014084015260a01c161515610160820152f35b3461032d57602036600319011261032d5761ffff612259613395565b1660005260cc602052602062ffffff60406000205460581c16604051908152f35b3461032d576122883661358e565b9092909190601081116122d7575090826122ad926122a8610c6e956138dd565b613bf7565b604051906020820152602081526122c38161350b565b6040519182916020835260208301906135ac565b9091906040106123a5576122ea8361392a565b9260005b6004811061233e57505050506040519060208083016000905b600482106123295750505050806080610c6e925261232481613527565b6122c3565b82806001928651815201940191019092612307565b806123578484876123516001968b613919565b51613bf7565b6123618288613919565b528061236e575b016122ee565b6123788187613919565b51865118604051602080820192835281526123928161350b565b51902061239f8288613919565b52612368565b634e487b7160e01b600052600160045260246000fd5b3461032d57600036600319011261032d57602060405160038152f35b3461032d57604036600319011261032d576123f0613395565b61ffff806123fc6133a6565b16918215612437571660005260d0602052604060002090600052602052602062ffffff60406000205460501c165b62ffffff60405191168152f35b9091501660005260cc602052602062ffffff604060002054821c1661242a565b3461032d57600036600319011261032d5761247061586f565b60006001600160a01b036097546001600160a01b03198116609755167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a3005b3461032d57600036600319011261032d5760207fffffffffffffffff00000000000000000000000000000000000000000000000060cb5460481b16604051908152f35b3461032d57600036600319011261032d576020604051620151808152f35b3461032d5760208060031936011261032d5760043567ffffffffffffffff811161032d576125459036906004016133c6565b9061254e61586f565b60005b828110612589576040517fb7bd806d66ef5249b63740995dc2366b90a3e2b78344eb5c0d573daa91971c68908061081d868683613f74565b61ffff61259a610278838686613eb2565b1660005260cc845260ff6040600020541660288110156108b957156125d557806102ae6125cb6125d0938686613eb2565b614358565b612551565b60046040517fdbab6626000000000000000000000000000000000000000000000000000000008152fd5b3461032d57602036600319011261032d5761ffff61261b613395565b6126236139b4565b501660005260d26020526102a0604060002060cc60205260ff61264b60406000205492613a38565b91612738604051809461ffff8082511683528060208301511660208401528060408301511660408401528060608301511660608401528060808301511660808401528060a08301511660a08401528060c08301511660c08401528060e08301511660e084015261010060ff818401511690840152610120818184015116908401526101408181840151169084015261016060ff818401511690840152610180818184015116908401526101a0818184015116908401526101c060ff8184015116908401526101e0818184015116908401526102009081830151169083015260ff6102208092015116910152565b6127486102408401838316613581565b62ffffff8160581c1661026084015260981c16610280820152f35b3461032d57600036600319011261032d576001600160a01b037f000000000000000000000000c6f268ddf4f9122cf47988dbd46fa0b103b8770f1630036127ce5760206040517f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc8152f35b60046040517f7251afea000000000000000000000000000000000000000000000000000000008152fd5b604036600319011261032d5761280c6133f7565b60243567ffffffffffffffff811161032d573660238201121561032d5780600401359061283882613565565b6128456040519182613543565b82815260209283820192366024838301011161032d578160009260248793018637830101526001600160a01b03807f000000000000000000000000c6f268ddf4f9122cf47988dbd46fa0b103b8770f1690813014612ae0577f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc918183541603612ab6576128d061586f565b7f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd91435460ff161561290857505050505061073b906158f5565b8516906040516352d1902d60e01b81528581600481865afa60009181612a87575b5061293f57600460405163081007d160e41b8152fd5b03612a5d5761294d856158f5565b604051907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b600080a2815115801590612a55575b61298757005b843b15612a2d575061073b93600092839251915af43d15612a25573d906129ad82613565565b916129bb6040519384613543565b82523d60008484013e5b7f416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c604051936129f3856134ef565b602785528401527f206661696c6564000000000000000000000000000000000000000000000000006040840152615962565b6060906129c5565b807f1fdb1d6d0000000000000000000000000000000000000000000000000000000060049252fd5b506001612981565b60046040517f8ae7e94c000000000000000000000000000000000000000000000000000000008152fd5b9091508681813d8311612aaf575b612a9f8183613543565b8101031261032d57519088612929565b503d612a95565b60046040517f36a15c6e000000000000000000000000000000000000000000000000000000008152fd5b60046040517f0ce7e818000000000000000000000000000000000000000000000000000000008152fd5b3461032d57612b183661340d565b909391612b2361586f565b801561191f578181036119495760005b818110612b6e5750907fbb9be5d1d0efdcb294acb14cca55a27436b316199041eb8cef7cac3d121a14c89461081d9260405195869586614a69565b612b8061027861ffff83168488614cfb565b612b8f61ffff83168589614d0b565b9061ffff861660005260d060205261ffff6040600020911660005260205260ff6040600020541660288110156108b95715612f2d577343da95dc00babae5d00ebea2c8088f3f7cd778323b1561032d576000612bff9160405180938192632ae2d1eb60e01b835260048301614d2e565b03817343da95dc00babae5d00ebea2c8088f3f7cd778325af48015610a7357612f1e575b50612c366115ae61ffff83168589614d0b565b9061ffff851660005260d0602052604060002061ffff612c5c610278828516878b614cfb565b1660005260205260406000209180519260288410156108b957612c8766ffff000000000094826142dd565b6020820151815464ffffffff00191660089190911b64ffffffff001617815563ffffffff916040810151825469ffffff00000000000000606084015160381b169169ffffffffff00000000001997889160281b1691161717825562ffffff6080612d0f828285015116859062ffffff60501b82549160501b169062ffffff60501b1916179055565b60a0830151845460c08086015160e087015171ffffffffff0000000000000000000000000019909316606894851b6effff00000000000000000000000000161760789190911b60ff60781b161760809290921b61ffff60801b169190911786559094600191610100860151825460ff60901b191660909190911b60ff60901b16178255856101208101519183549060ff60a81b61014084015160a81b169060ff60c01b61ffff60b01b61016086015160b01b1691610180860151901b1660ff60c81b6101a086015160c81b169161ffff60d01b6101c087015160d01b169361ffff60e01b6101e088015160e01b169572ffffffffffffffffffffffffffffffffffffff61ffff60981b6001600160f81b031961022060ff60f01b6102008d015160081c169b0151169a60981b169116171717171717171717815501946102408401519060288210156108b9576117e5612e6892886142dd565b6102808301519060288210156108b957612ef672ffffffffffff0000000000000000000000000019936fffffff000000000000000000000000009360019a89549065ff000000000069ffffffff0000000000006102a08b015160301b169360281b169116171788556102c086015116879062ffffff60501b82549160501b169062ffffff60501b1916179055565b62ffffff60801b6102e0850151916103008854960151901b16941b1691161717905501612b33565b612f2790613484565b86612c23565b60046040517f510fec52000000000000000000000000000000000000000000000000000000008152fd5b3461032d5760208060031936011261032d5760e09061ffff612f77613395565b600060c0604051612f8781613468565b82815282868201528260408201528260608201528260808201528260a082015201521660005260d18152604060002060405190612fc382613468565b5460019181830b93848252808201908360101c850b82526040830184821c860b815260608401918560301c870b835260808501938660401c880b855260c060a08701968860501c8a0b8852019660601c880b875260405198895251870b9088015251850b604087015251840b606086015251830b608085015251820b60a084015251900b60c0820152f35b3461032d57602036600319011261032d5761ffff61306a613395565b1660005260cc6020526040806000205463ffffffff82519160ff8160901c16835260381c166020820152f35b3461032d5760208060031936011261032d576130b06133f7565b906001600160a01b03807f000000000000000000000000c6f268ddf4f9122cf47988dbd46fa0b103b8770f16803014612ae0577f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc908282541603612ab65761311661586f565b604051908382019282841067ffffffffffffffff851117610d9457836040526000835260ff7f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143541660001461317357505050505061073b906158f5565b8516906040516352d1902d60e01b81528581600481865afa600091816131f9575b506131aa57600460405163081007d160e41b8152fd5b03612a5d576131b8856158f5565b604051907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b600080a28151158015906131f15761298757005b506000612981565b9091508681813d8311613221575b6132118183613543565b8101031261032d57519088613194565b503d613207565b3461032d57602036600319011261032d576004356001600160a01b03811680910361032d5761325561586f565b6001600160a01b031960d354161760d355600080f35b3461032d57604036600319011261032d57613284613395565b60243567ffffffffffffffff811161032d576132a49036906004016133c6565b90916132ae61586f565b811561191f5761ffff9081169060005b83811061330557505061081d7f32fe84254806f7c0fd6cbd970048ace22c87c23fb04b33e52b3115d7ff485a5a9360405193849384526040602085015260408401916149f3565b60019083600052602060d08152604060002090846133296102788286168a8c614cfb565b1660005252600082604082208281550155016132be565b3461032d57611e706133513661337f565b9061374f565b3461032d57602036600319011261032d576020613375600435613863565b1515604051908152f35b604090600319011261032d576004359060243590565b6004359061ffff8216820361032d57565b6024359061ffff8216820361032d57565b359061ffff8216820361032d57565b9181601f8401121561032d5782359167ffffffffffffffff831161032d576020808501948460051b01011161032d57565b600435906001600160a01b038216820361032d57565b90606060031983011261032d5760043561ffff8116810361032d579167ffffffffffffffff9160243583811161032d578261344a916004016133c6565b9390939260443591821161032d57613464916004016133c6565b9091565b60e0810190811067ffffffffffffffff821117610d9457604052565b67ffffffffffffffff8111610d9457604052565b610180810190811067ffffffffffffffff821117610d9457604052565b610240810190811067ffffffffffffffff821117610d9457604052565b610320810190811067ffffffffffffffff821117610d9457604052565b6060810190811067ffffffffffffffff821117610d9457604052565b6040810190811067ffffffffffffffff821117610d9457604052565b60a0810190811067ffffffffffffffff821117610d9457604052565b90601f8019910116810190811067ffffffffffffffff821117610d9457604052565b67ffffffffffffffff8111610d9457601f01601f191660200190565b9060288210156108b95752565b608090600319011261032d5760043590602435906044359060643590565b919082519283825260005b8481106135d8575050826000602080949584010152601f8019910116010190565b6020818301810151848301820152016135b7565b60c9548110156136235760c96000527f66be4f155c5ef2ebd3772b228f2f00681e4ed5826cdb3b1943cc11ad15ad1d280190600090565b634e487b7160e01b600052603260045260246000fd5b80548210156136235760005260206000200190600090565b604060031982011261032d576004359160243567ffffffffffffffff9283821161032d578060238301121561032d57816004013593841161032d5760248460061b8301011161032d576024019190565b91908203918211610ab657565b906205460064ffffffffff80931601918211610ab657565b9062093a8064ffffffffff80931601918211610ab657565b9062093a8064ffffffffff80931602918216918203610ab657565b91908201809211610ab657565b60c95468010000000000000000811015610d945780600161372a920160c9556135ec565b819291549060031b91821b91600019901b1916179055565b8051156136235760200190565b61379e6137b19267ffffffffffffffff60cb5460781c168360005260d5602052604060002054916040519060208201928352604082015260408152613793816134ef565b51902060381c613bd7565b9060005260d56020526040600020613639565b50549062ffffff61ffff83169260101c1690565b9193929360009483865260d460205260408620549260405190602082019283526040820152604081526137f7816134ef565b519020908060031b908082046008149015171561382f576040926137b1959692613821921c613bd7565b92815260d460205220613639565b602486634e487b7160e01b81526011600452fd5b6000198114610ab65760010190565b9060088110156136235760051b0190565b61386c906138ae565b6000811280156138a2575b61389c57613884906135ec565b90549060031b1c60005260ca60205260406000205490565b50600090565b508060c9541115613877565b64ffffffffff60cb5460281c16908181106138d55762015180916138d1916136a1565b0490565b505060001990565b6138e690613863565b9081156138ef57565b60046040517fb4190460000000000000000000000000000000000000000000000000000000008152fd5b9060048110156136235760051b0190565b6040516080810181811067ffffffffffffffff821117610d945760405260803682378091600090815b6004808210156139ac576201518090818302918383041483151715613999575090613988613983600193856136a1565b6138dd565b6139928287613919565b5201613953565b846011602492634e487b7160e01b835252fd5b505050505090565b604051906139c1826134b5565b816102206000918281528260208201528260408201528260608201528260808201528260a08201528260c08201528260e08201528261010082015282610120820152826101408201528261016082015282610180820152826101a0820152826101c0820152826101e0820152826102008201520152565b90604051613a45816134b5565b61022081935461ffff8082168452808260101c166020850152808260201c166040850152808260301c166060850152808260401c166080850152808260501c1660a0850152808260601c1660c0850152808260701c1660e085015260ff8260801c16610100850152808260881c16610120850152808260981c1661014085015260ff8260a81c16610160850152808260b01c16610180850152808260c01c166101a085015260ff8260d01c166101c0850152808260d81c166101e08501528160e81c1661020084015260f81c910152565b60288210156108b95752565b60405190613b2f826134d2565b816103006000918281528260208201528260408201528260608201528260808201528260a08201528260c08201528260e08201528261010082015282610120820152826101408201528261016082015282610180820152826101a0820152826101c0820152826101e08201528261020082015282610220820152826102408201528261026082015282610280820152826102a0820152826102c0820152826102e08201520152565b8115613be1570690565b634e487b7160e01b600052601260045260246000fd5b929091604051926020840194855260408401526060830152608082015260808152613c2181613527565b51902090565b9060009082825260ca60205260409081832054613e89576001815103613e6057613c5090613742565b51928315613e37575b80835260ca60205283828420556001600160a01b038060d3541680613de7575b5060d6541680613d86575b50907f5c69e7026b653d8606b5613bb00fd8c4b0504b1cbe8db600c406faac180924d5918151908152846020820152a160cb54906201518090814204828102928184041490151715613d725764ffffffffff91828460501c161115613cea575b50505050565b620545ff19420190428211613d7257506effffffffff00000000000000000000613d5961112c6111277fffffffffffffffffff00000000000000000000000000ffffffffffffffffffff9562093a8076ffffffffffffffff0000000000000000000000000000009604166136de565b60501b169360781b169116171760cb5538808080613ce4565b80634e487b7160e01b602492526011600452fd5b803b15613de35783809160248551809481936327fe556d60e21b83528a60048401525af18015613dd657908491613dbe575b50613c84565b613dc790613484565b613dd2578238613db8565b8280fd5b50505051903d90823e3d90fd5b8380fd5b803b15613e335784809160248651809481936327fe556d60e21b83528b60048401525af18015613e295715613c7957613e2290949194613484565b9238613c79565b84513d87823e3d90fd5b8480fd5b92506000194301438111613e4c574092613c59565b602483634e487b7160e01b81526011600452fd5b600482517fff633a38000000000000000000000000000000000000000000000000000000008152fd5b600482517f533d99dd000000000000000000000000000000000000000000000000000000008152fd5b91908110156136235760051b810135906102be198136030182121561032d570190565b3590811515820361032d57565b359062ffffff8216820361032d57565b359063ffffffff8216820361032d57565b359060ff8216820361032d57565b602090613f2f8261ffff9283613f26826133b7565b168652016133b7565b16910152565b60ff613f2f6040809361ffff80613f4b836133b7565b168752613f5a602083016133b7565b16602087015201613f03565b35908160010b820361032d57565b91602090808285018386525260409182850194838360051b82010195856000925b858410613fa757505050505050505090565b9091929394959697603f1982820301845288356102be198436030181121561032d576102c09190840161ffff83830181613fe0846133b7565b16845289830135602881101561032d57613ffd908b860190613581565b6140088c8401613ed5565b15158c85015260609161401c838501613ed5565b151583860152608061402f818601613ed5565b15159086015262ffffff60a081614047828801613ee2565b169087015260c063ffffffff61405e828801613ef2565b169087015260e090614071828701613ee2565b1690860152610100816140858287016133b7565b1690860152610120906140998286016133b7565b169085015260ff610140816140af828701613f03565b1690860152610160906140c3828601613f03565b16908501526101806140d6818501613ed5565b15159085015236839003601e19016101a0848101358281121561032d578501908c823592019367ffffffffffffffff9889841161032d578360061b3603861361032d578392890152528d6102e0870193916000915b81831061424e57505050506101c090818501359081121561032d578401918b8335930196831161032d578383023603871361032d5780869594928d97889303908701528381520195916000915b81831061422757505050509282916001946101e0614197818301613f66565b870b90830152856102006141ac838201613f66565b820b908401526102206141c0818401613f66565b820b908401526102406141d4818401613f66565b820b908401526102606141e8818401613f66565b820b908401526102806141fc818401613f66565b820b908401526142106102a0809301613f66565b900b9101529a019401940192969594939190613f95565b808093959697508861423d869a60019597613f35565b019701930190918b95949392614178565b808661425f86986001959697613f11565b0195019201908f61412b565b35801515810361032d5790565b3561ffff8116810361032d5790565b3562ffffff8116810361032d5790565b903590601e198136030182121561032d570180359067ffffffffffffffff821161032d57602001918160061b3603831361032d57565b91908110156136235760061b0190565b9060288110156108b95760ff80198354169116179055565b3563ffffffff8116810361032d5790565b3560ff8116810361032d5790565b903590601e198136030182121561032d570180359067ffffffffffffffff821161032d5760200191606082023603831361032d57565b358060010b810361032d5790565b61436181614278565b61ffff916000918316156149c95761010081019161437e83614278565b610120830190858061438f84614278565b1691161161499f5760e083019162ffffff806143aa85614287565b161561493d576143b984614287565b168015614929576236ee80066148ff575b856143d485614278565b16815260209460cc865260409283832087870135916028831015613e33576143fc83836142dd565b61440788870161426b565b15158254946060988a8c8b820161441d9061426b565b1515608083019961442d8b61426b565b151560181b63ff000000169260a0850161444690614287565b901b66ffffff00000000169360c00161445e906142f5565b60381b6affffffff00000000000000169461447890614287565b60581b6dffffff0000000000000000000000169561449590614278565b60701b6fffff0000000000000000000000000000169660081b61ff0016907fffffffffffffffffffffffffffffffff000000000000000000000000000000ff16179060101b62ff00001617171717171782556144f090614278565b81547fffffffffffffffffffffffffffff0000ffffffffffffffffffffffffffffffff1660809190911b61ffff60801b161781556145316101408801614306565b815460ff60901b191660909190911b60ff60901b161781556145566101608801614306565b81546145656101808a0161426b565b151560a01b74ff0000000000000000000000000000000000000000169160981b73ff0000000000000000000000000000000000000016907fffffffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffff1617179055876145cc87614278565b16835260d28752838320886145e088614278565b16845283858120557343da95dc00babae5d00ebea2c8088f3f7cd77832916101a088019161460e838a614297565b90853b156148fb579087895180937f1a2bbf3d00000000000000000000000000000000000000000000000000000000825283604483018d600485015252606482019093835b8d8282106148d857505050819293508560248301520381885af480156148ce576148bb575b506101c0890193614689858b614314565b92823b156148b75791899189938c8685519788967f91f221eb000000000000000000000000000000000000000000000000000000008852604488019060048901525260648601939187905b82821061488d575050505083918291602483015203915af480156148835790869161486f575b50506001036147f45750505081908661471286614278565b16815260d1865220946147286101e0850161434a565b94865461020086016147399061434a565b60101b9161474a610220880161434a565b901b9261475a610240880161434a565b60301b9461476b610260890161434a565b901b9561477b610280890161434a565b60501b976102a00161478c9061434a565b901b6dffff000000000000000000000000169716906dffffffffffffffffffffffffffff1916179063ffff000016179065ffff0000000016179067ffff00000000000016179069ffff00000000000000001617906bffff000000000000000000001617179055565b91959650929650614815935061480b915085614297565b9050151593614314565b905082614865575b5081614855575b5061482c5750565b600490517fb28b6f38000000000000000000000000000000000000000000000000000000008152fd5b61485f915061426b565b38614824565b151591503861481d565b61487890613484565b613e335784386146fa565b87513d88823e3d90fd5b91948291949698508397506148a481600195613f35565b0195019101908694928c9694928f6146d4565b8880fd5b6148c790969196613484565b9438614678565b88513d89823e3d90fd5b919450925080826148eb60019488613f11565b0194019101928a92859294614653565b8780fd5b60046040517ffbf84394000000000000000000000000000000000000000000000000000000008152fd5b602482634e487b7160e01b81526012600452fd5b506101a0840161494d8186614297565b905061495a575b506143ca565b6149649085614297565b1561498b576149766020889201614278565b16801561492957618ca0066148ff5738614954565b602482634e487b7160e01b81526032600452fd5b60046040517f3ab272e6000000000000000000000000000000000000000000000000000000008152fd5b60046040517fc78a7d8b000000000000000000000000000000000000000000000000000000008152fd5b91908082526020809201929160005b828110614a10575050505090565b90919293828060019261ffff614a25896133b7565b16815201950193929101614a02565b9035601e198236030181121561032d57016020813591019167ffffffffffffffff821161032d578160051b3603831361032d57565b949192909461ffff8096168152614a8d6060946020938685850152868401916149f3565b906040908181840391015283825282820194838560051b84010197876000945b878610614ac1575050505050505050505090565b90919293949596979899601f19828203018a528a356101be198436030181121561032d57830190602882358181101561032d5791614b00818c94613581565b614b0b838501613f66565b91600192830b8483015262ffffff80614b258c8801613ee2565b168b84015280614b368b8801613ee2565b168a840152614b5e6080614b4c81890189614a34565b90916101c080918801528601916149f3565b60a09186614b6e848a018a614a34565b939094878203908801528381520192916000915b818310614cd4575050505060c089614b9b8289016133b7565b169084015260ff60e081614bb0828a01613f03565b169085015261010090614bc4828901613f03565b169084015261012089614bd88289016133b7565b169084015261014089614bec8289016133b7565b1690840152610160614bff818801613ed5565b1515908401526101809185614c1684890189614a34565b939094868203908701528381520192916000915b818310614ca357505050508390614c476101a09687810190614a34565b9390968183039101528281520193916000915b808310614c7d5750505050806001929c019a019601949392919097969597614aad565b919380849663ffffffff614c918597613ef2565b168152019501930190918b9392614c5a565b919390928095975035908282101561032d578f81614cc382938a95613581565b019501930190918e96949392614c2a565b9193978084979984614ce78b9597613ee2565b168152019601930190918f97959392614b82565b91908110156136235760051b0190565b91908110156136235760051b810135906101be198136030182121561032d570190565b60208082526101e0820190602884358181101561032d57614d559083869594960190613581565b614d60848601613f66565b92600193840b604082015262ffffff9586614d7d60408301613ee2565b16606083015286614d9060608301613ee2565b166080830152614da36080820182614a34565b806101c0999299968760a0870152526102008401989060005b818110614f5357505050614dd360a0830183614a34565b601f19858b03810160c0870152818b52998901926000905b828210614f2b5750505050614e7d614e6b61ffff80614e0c60c087016133b7565b1660e0870152614e5b81614e4b60ff614e3b81614e2b60e08c01613f03565b1661010090818d01528a01613f03565b1661012090818b015288016133b7565b16610140908189015286016133b7565b1661016090818701528401613ed5565b15156101809081860152830183614a34565b8483038a016101a086810191909152818452928901956000905b828210614efa575050505081614eb291889594930190614a34565b9490978284030191015282815201939260005b828110614ed457505050505090565b9091928280869763ffffffff614eea8599613ef2565b1681520196019493929101614ec5565b90919296879a98999a35908282101561032d578981614f1b82938f95613581565b9a9c9b9a01980193920190614e97565b90919293988a80829c9a9b84614f4089613ee2565b1681529a9c9b9a01950193920190614deb565b909199978980829b999a61ffff614f698f6133b7565b168152019b989a999801929101614dbc565b903590601e198136030182121561032d570180359067ffffffffffffffff821161032d57602001918160051b3603831361032d57565b614fb9613b22565b50614fc7610160820161426b565b6000901561579757506001600160f81b031960805b60f81b1680610200526001614ff5610180840184614f7b565b90501161576b575b5061500b60a0820182614f7b565b9050151580615742575b80156156fa575b8060a052156156ab575b60a05161567c575b60288135101561032d576150466101a0820182614f7b565b6000608052159050615677576150606101a0820182614f7b565b156136235761506e906142f5565b6080525b61507e6020820161434a565b60c05261508d60408201614287565b60e05261509c60608201614287565b906150aa6080820182614f7b565b600091501561567157506150c16080820182614f7b565b15613623576150cf90614278565b915b6150de60a0830183614f7b565b9050151580615667575b6000901561566157506150fe60a0830183614f7b565b156136235761510e60ff91614287565b16905b61511e6080840184614f7b565b600091506001101561565b57506151386080840184614f7b565b6001101561362357602061514c9101614278565b925b600161515d60a0830183614f7b565b90501180615651575b6000901561564b575061517c60a0820182614f7b565b6001101561362357615192602060ff9201614287565b16925b6151a26080830183614f7b565b600091506002101561564557506151bc6080830183614f7b565b600210156136235760406151d09101614278565b945b60026151e160a0850185614f7b565b9050118061563b575b60009015615635575061520060a0840184614f7b565b6002101561362357615216604060ff9201614287565b16935b61522560c08501614278565b9061523260e08601614306565b916152406101008701614306565b9461524e6101208801614278565b9761525c6101408901614278565b9a600161526d6101808b018b614f7b565b9050600061010052116000146156305761528b6101808a018a614f7b565b600110156136235760200135602881101561032d57610100525b60016152b56101a08b018b614f7b565b90506000610120521160001461562b576152d36101a08a018a614f7b565b600110156136235760206152e791016142f5565b610120525b60026152fc6101808b018b614f7b565b9050600061016052116000146156265761531a6101808a018a614f7b565b600210156136235760400135602881101561032d57610160525b60026153446101a08b018b614f7b565b905060006101405211600014615621576153626101a08a018a614f7b565b6002101561362357604061537691016142f5565b610140525b61538860a08a018a614f7b565b9050151580615618575b60006101805215615613576153aa60a08a018a614f7b565b15613623576153b890614287565b610180525b60016153cc60a08b018b614f7b565b9050118061560a575b60006101a05215615605576153ed60a08a018a614f7b565b600110156136235760206154019101614287565b6101a0525b600261541560a08b018b614f7b565b905011806155fc575b60006101c052156155d75761543660a08a018a614f7b565b600292919210156136235760ff61ffff9e9c8f829c9a819f849c9883869a9262ffffff829e61548c8a9661546d6040879f01614287565b6101c0525b615482604051806101e0526134d2565b356101e051613b16565b63ffffffff6080511660206101e051015260c05160010b60406101e05101528160e0511660606101e05101521660806101e05101521660a06101e05101521660c06101e05101521660e06101e0510152166101006101e0510152166101206101e0510152166101406101e0510152166101606101e0510152166101806101e0510152166101a06101e0510152166101c06101e0510152166101e0805101526001600160f81b031961020051166102006101e051015260006102206101e0510152615560610100516102406101e05101613b16565b63ffffffff61012051166102606101e0510152615587610160516102806101e05101613b16565b63ffffffff61014051166102a06101e051015262ffffff61018051166102c06101e051015262ffffff6101a051166102e06101e051015262ffffff6101c051166103006101e05101526101e05190565b61ffff9c9060ff8e9c8d829c9a83809c9883809c9862ffffff829a61548c869e615472565b5060a05161541e565b615406565b5060a0516153d5565b6153bd565b5060a051615392565b61537b565b615334565b6152ec565b6152a5565b93615219565b5060a051156151ea565b946151d2565b92615195565b5060a05115615166565b9261514e565b90615111565b5060a051156150e8565b916150d1565b615072565b7f200000000000000000000000000000000000000000000000000000000000000061020051176102005261502e565b60026156ba60a0830183614f7b565b905011806156cb575b60a052615026565b506156d960a0820182614f7b565b600210156136235762ffffff6156f3604060ff9301614287565b16116156c3565b50600161570a60a0830183614f7b565b905011801561501c575061572160a0820182614f7b565b600110156136235762ffffff61573b602060ff9301614287565b161161501c565b5061575060a0820182614f7b565b156136235762ffffff61576460ff92614287565b1611615015565b7f4000000000000000000000000000000000000000000000000000000000000000176102005238614ffd565b6001600160f81b031990614fdc565b90821015613623576134649160051b810190614f7b565b805490600090818155826157d057505050565b815260208120918201915b8281106157e757505050565b8181556001016157db565b805468010000000000000000811015610d945761581491600182018155613639565b9190916158595761ffff61582782614278565b1664ffffff000061584660208554948461ffff19871617875501614287565b60101b169164ffffffffff191617179055565b634e487b7160e01b600052600060045260246000fd5b6001600160a01b0360975416330361588357565b60046040517f6db2465f000000000000000000000000000000000000000000000000000000008152fd5b609754906001600160a01b0380911691826001600160a01b0319821617609755167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a3565b803b15615938576001600160a01b037f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc91166001600160a01b0319825416179055565b60046040517f71ab98ae000000000000000000000000000000000000000000000000000000008152fd5b9091901561596e575090565b81511561597e5750805190602001fd5b6159bc906040519182917f08c379a00000000000000000000000000000000000000000000000000000000083526020600484015260248301906135ac565b0390fdfea26469706673582212203a8c6106c01cc9fed6bfcfd415a98ad454ebc5441c507e78519a1853359a96d564736f6c63430008140033

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
[ Download: CSV Export  ]

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.