ETH Price: $2,360.22 (+0.85%)

Staked FrankenPunks (sFP)
 

Overview

TokenID

1361

Total Transfers

-

Market

Onchain Market Cap

$0.00

Circulating Supply Market Cap

-
Loading...
Loading
Loading...
Loading
Loading...
Loading

Click here to update the token information / general information
# Exchange Pair Price  24H Volume % Volume

Contract Source Code Verified (Exact Match)

Contract Name:
Staking

Compiler Version
v0.8.17+commit.8df45f5f

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion
File 1 of 13 : Staking.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;

/**
 _______  _______  _______  _        _        _______  _          _______           _        _        _______
(  ____ \(  ____ )(  ___  )( (    /|| \    /\(  ____ \( (    /|  (  ____ )|\     /|( (    /|| \    /\(  ____ \
| (    \/| (    )|| (   ) ||  \  ( ||  \  / /| (    \/|  \  ( |  | (    )|| )   ( ||  \  ( ||  \  / /| (    \/
| (__    | (____)|| (___) ||   \ | ||  (_/ / | (__    |   \ | |  | (____)|| |   | ||   \ | ||  (_/ / | (_____
|  __)   |     __)|  ___  || (\ \) ||   _ (  |  __)   | (\ \) |  |  _____)| |   | || (\ \) ||   _ (  (_____  )
| (      | (\ (   | (   ) || | \   ||  ( \ \ | (      | | \   |  | (      | |   | || | \   ||  ( \ \       ) |
| )      | ) \ \__| )   ( || )  \  ||  /  \ \| (____/\| )  \  |  | )      | (___) || )  \  ||  /  \ \/\____) |
|/       |/   \__/|/     \||/    )_)|_/    \/(_______/|/    )_)  |/       (_______)|/    )_)|_/    \/\_______)

*/

import "solmate/tokens/ERC721.sol";
import "solmate/utils/LibString.sol";
import "./utils/SafeCast.sol";
import "./utils/Refundable.sol";
import "./utils/Admin.sol";

import "./interfaces/IERC721.sol";
import "./interfaces/IStaking.sol";
import "./interfaces/IGovernance.sol";
import "./interfaces/IExecutor.sol";

/// @title FrankenDAO Staking
/// @author Zach Obront & Zakk Fleischmann
/// @notice Users stake FrankenPunks & FrankenMonsters and get ERC721s in return
/// @notice These ERC721s are used for voting power for FrankenDAO governance
contract Staking is IStaking, ERC721, Admin, Refundable {
  using LibString for uint256;

  /// @notice The original ERC721 FrankenPunks contract
  IERC721 frankenpunks;
  
  /// @notice The original ERC721 FrankenMonsters contract
  IERC721 frankenmonsters;

  /// @notice The DAO governance contract (where voting occurs)
  IGovernance governance;

  /// @notice Base votes for holding a Frankenpunk token
  uint constant public BASE_VOTES = 20;

  /// @return maxStakeBonusTime The maxmimum time you will earn bonus votes for staking for
  /// @return maxStakeBonusAmount The amount of bonus votes you'll get if you stake for the max time
  StakingSettings public stakingSettings;

  /// @notice Multipliers (expressed as percentage) for calculating community voting power from user stats
  /// @return votes The multiplier for extra voting power earned per DAO vote cast
  /// @return proposalsCreated The multiplier for extra voting power earned per proposal created
  /// @return proposalsPassed The multiplier for extra voting power earned per proposal passed
  CommunityPowerMultipliers public communityPowerMultipliers;

  /// @notice Constant to calculate voting power based on multipliers above
  uint constant PERCENT = 100;

  /// @notice Are refunds turned on for staking?
  bool public stakingRefund;

  /// @notice The last timestamp at which a user used their staking refund
  mapping(address => uint256) public lastStakingRefund;

  /// @notice Are refunds turned on for delegating?
  bool public delegatingRefund;

  /// @notice The last timestamp at which a user used their delegating refund
  mapping(address => uint256) public lastDelegatingRefund;

  /// @notice How often can a user use their refund?
  uint256 public refundCooldown;

  /// @notice Is staking currently paused or open?
  bool public paused;

  /// @notice The staked time bonus for each staked token (tokenId => bonus votes)
  /// @dev This needs to be tracked because users will select how much time to lock for, so bonus is variable
  mapping(uint => uint) stakedTimeBonus; 
  
  /// @notice The allowed unlock time for each staked token (tokenId => timestamp)
  /// @dev This remains at 0 if tokens are staked without locking
  mapping(uint => uint) public unlockTime;

  /// @notice Addresses that each user delegates votes to
  /// @dev This should only be accessed via getDelegate() function, which overrides address(0) with self
  mapping(address => address) private _delegates;

  /// @notice The total voting power earned by each user's staked tokens
  /// @dev In other words, this is the amount of voting power that would move if they redelegated
  /// @dev They don't necessarily have this many votes, because they may have delegated them
  mapping(address => uint) public votesFromOwnedTokens;

  /// @notice The total voting power each user has, after adjusting for delegation
  /// @dev This represents the actual token voting power of each user
  mapping(address => uint) public tokenVotingPower;

  /// @notice The total token voting power of the system
  uint totalTokenVotingPower;

  /// @notice Base token URI for the ERC721s representing the staked position
  string public baseTokenURI;

  /// @notice Contract URI for marketplace metadata
  string public contractURI;

  /// @notice The total supply of staked frankenpunks
  uint128 public stakedFrankenPunks;

  /// @notice The total supply of staked frankenmonsters
  uint128 public stakedFrankenMonsters;

  /// @notice Bitmaps representing whether each FrankenPunk has a sufficient "evil score" for a bonus.
  /// @dev 40 words * 256 bits = 10,240 bits, which is sufficient to hold values for 10k FrankenPunks
  uint[40] EVIL_BITMAPS = [
    883425322698150530263834307704826599123904599330160270537777278655401984, // 0
    14488147225470816109160058996749687396265978336526515174837584423109802852352, // 1
    38566513062215815139428642218823858442255833421860837338906624, // 2
    105312291668557186697918027683670432324476705909712387428719788032, // 3
    14474011154664524427946373126085988481660077311200856629730921422678596263936, // 4
    3618502788692465607655909614339766499850336868450542774889103259212619972609, // 5
    441711772776714745308416192199486840791445460561420424832198410539892736, // 6
    6901746759773641161995257390185172072446268286034776944761674561224712, // 7
    883423532414903565819785182543377466397133986207912949084155019599544320, // 8
    14474011155086185177904289442148664541270784730116237084843513087002589265920, // 9
    107839786668798718607898896909541540930351713584408019687362806153216, // 10
    904625700641838402593673198335004289144275540958779302917589231213362556944, // 11
    220859253090631447287862539909960206022391538433640386622889848771706880, // 12
    1393839110204029063653915313866451565150208, // 13
    784637716923340670665773318162647287385528792673206407169, // 14
    107839786668602559178668060353525740564723109496935832847049186869248, // 15
    51422802054004612152481822571560984362335820545231474237898784, // 16
    6582018229284824169333500576582381960460086447259084614308728832, // 17
    365732221255902219560809532335122355265736818688, // 18
    445162639419413381705829464770174011933371831432841644599383048677490688, // 19
    6935446280124502090171244984389489167294584349705235353545399909482504, // 20
    452312848583266388373372050675839373643513806386188657447441353755011973120, // 21
    51422023594160337932957247212003666383914706547133656225284128, // 22
    2923003274661805998666646494941077336069228208128, // 23
    215679573337205118357336126271343355406346657833909405071980653182976, // 24
    26959946667150639794667015087041235820865508444839585222888876146720, // 25
    3731581108651760187459529718884681603688140590625042088037390915407571845120, // 26
    33372889303170710042455474178259135664197736114694375141005066752, // 27
    28948022309329151699928351061631107912622119818910282538292189430411643863044, // 28
    55214023430470347690952963241066788995217469738067023806554216123598848, // 29
    55213971185700649632772712790212230970723509677757939395778641765335297, // 30
    50216813883139118038214077107913983031541181002059654103040, // 31
    45671926166601100787582220677640905906662146176, // 32
    431359146674410260659915067596052074490887103277477952745659311325184, // 33
    6741683593362397442763285474207733540211166501858783908538903166976, // 34
    421249166674235107246797774824181756792478284093098635821743865856, // 35
    53919893334350319447007114026840783409769671338355940037889148190720, // 36
    401740641047276407850947922339698016834483256774579142524928, // 37
    220855883097304318299647574273628650268020954052697685772267193358090240, // 38
    0 // 39
  ];

  /////////////////////////////////
  /////////// MODIFIERS ///////////
  /////////////////////////////////

  /// @dev To avoid needing to checkpoint voting power, tokens are locked while users have active votes cast or proposals open
  /// @dev If a user creates a proposal or casts a vote, this modifier prevents them from unstaking or delegating
  /// @dev Once the proposal is completed, it is removed from getActiveProposals and their tokens are unlocked
  modifier lockedWhileVotesCast() {
    uint[] memory activeProposals = governance.getActiveProposals();
    for (uint i = 0; i < activeProposals.length; i++) {
      if (governance.getReceipt(activeProposals[i], getDelegate(msg.sender)).hasVoted) revert TokenLocked();
      (, address proposer,) = governance.getProposalData(activeProposals[i]);
      if (proposer == getDelegate(msg.sender)) revert TokenLocked();
    }
    _;
  }

  /////////////////////////////////
  ////////// CONSTRUCTOR //////////
  /////////////////////////////////

  /// @param _frankenpunks The address of the original ERC721 FrankenPunks contract
  /// @param _frankenmonsters The address of the original ERC721 FrankenMonsters contract
  /// @param _governance The address of the DAO governance contract
  /// @param _executor The address of the DAO executor contract
  /// @param _founders The address of the founder multisig for restricted functions
  /// @param _council The address of the council multisig for restricted functions
  /// @param _baseTokenURI Token URI for the Staking NFT contract
  /// @param _contractURI URI for the contract metadata
  constructor(
    address _frankenpunks, 
    address _frankenmonsters,
    address _governance, 
    address _executor, 
    address _founders,
    address _council,
    string memory _baseTokenURI,
    string memory _contractURI
  ) ERC721("Staked FrankenPunks", "sFP") {
    frankenpunks = IERC721(_frankenpunks);
    frankenmonsters = IERC721(_frankenmonsters);
    governance = IGovernance( _governance );

    executor = IExecutor(_executor);
    founders = _founders;
    council = _council;

    // Staking bonus increases linearly from 0 to 20 votes over 4 weeks
    stakingSettings = StakingSettings({
      maxStakeBonusTime: uint128(4 weeks), 
      maxStakeBonusAmount: uint128(20)
    });

    // Users get a bonus 1 vote per vote, 2 votes per proposal created, and 2 votes per proposal passed
    communityPowerMultipliers = CommunityPowerMultipliers({
      votes: uint64(100), 
      proposalsCreated: uint64(200),
      proposalsPassed: uint64(200)
    });

    // Refunds are initially turned on with 1 day cooldown.
    delegatingRefund = true;
    stakingRefund = true;
    refundCooldown = 1 days;

    // Set the base token URI.
    baseTokenURI = _baseTokenURI;

    // Set the contract URI.
    contractURI = _contractURI;
  }

  /////////////////////////////////
  // OVERRIDE & REVERT TRANSFERS //
  /////////////////////////////////  

  /// @notice Transferring of staked tokens is prohibited, so all transfers will revert
  /// @dev This will also block safeTransferFrom, because of solmate's implementation
  function transferFrom(address, address, uint256) public pure override(ERC721) {
    revert StakedTokensCannotBeTransferred();
  }

  /////////////////////////////////
  /////// TOKEN URI FUNCTIONS /////
  /////////////////////////////////

  /// @notice Token URI to find metadata for each tokenId
  /// @dev The metadata will be a variation on the metadata of the underlying token
  function tokenURI(uint256 _tokenId) public view virtual override(ERC721) returns (string memory) {
    if (ownerOf(_tokenId) == address(0)) revert NonExistentToken();

    string memory baseURI = baseTokenURI;
    return bytes(baseURI).length > 0
      ? string(abi.encodePacked(baseURI, _tokenId.toString(), ".json"))
      : "";
  }

  /////////////////////////////////
  /////// DELEGATION LOGIC ////////
  /////////////////////////////////

  /// @notice Return the address that a given address delegates to
  /// @param _delegator The address to check 
  /// @return The address that the delegator has delegated to
  /// @dev If the delegator has not delegated, this function will return their own address
  function getDelegate(address _delegator) public view returns (address) {
    address current = _delegates[_delegator];
    return current == address(0) ? _delegator : current;
  }

  /// @notice Delegate votes to another address
  /// @param _delegatee The address you wish to delegate to
  /// @dev Refunds gas if delegatingRefund is true and hasn't been used by this user in the past 24 hours
  function delegate(address _delegatee) public {
    if (_delegatee == address(0)) _delegatee = msg.sender;
    
    // Refunds gas if delegatingRefund is true and hasn't been used by this user in the past 24 hours
    if (delegatingRefund && lastDelegatingRefund[msg.sender] + refundCooldown <= block.timestamp) {
      uint256 startGas = gasleft();
      _delegate(msg.sender, _delegatee);
      lastDelegatingRefund[msg.sender] = block.timestamp;
      _refundGas(startGas);
    } else {
      _delegate(msg.sender, _delegatee);
    }
  }

  /// @notice Delegates votes from the sender to the delegatee
  /// @param _delegator The address of the user who called the function and owns the votes being delegated
  /// @param _delegatee The address of the user who will receive the votes
  function _delegate(address _delegator, address _delegatee) internal lockedWhileVotesCast {
    address currentDelegate = getDelegate(_delegator);
    // If currentDelegate == _delegatee, then this function will not do anything
    if (currentDelegate == _delegatee) revert InvalidDelegation();

    // Set the _delegates mapping to the correct address, subbing in address(0) if they are delegating to themselves
    _delegates[_delegator] = _delegatee == _delegator ? address(0) : _delegatee;
    uint amount = votesFromOwnedTokens[_delegator];

    // If the delegator has no votes, then this function will not do anything
    // This is explicitly blocked to ensure that users without votes cannot abuse the refund mechanism
    if (amount == 0) revert InvalidDelegation();
    
    // Move the votes from the currentDelegate to the new delegatee
    // Neither of these addresses can be address(0) because: 
    // - currentDelegate calls getDelegate(), which replaces address(0) with the delegator's address
    // - delegatee is changed to msg.sender in the external functions if address(0) is passed
    tokenVotingPower[currentDelegate] -= amount;
    tokenVotingPower[_delegatee] += amount; 

    // If this moved the current delegate down to zero voting power, then remove their community VP from the totals
    if (tokenVotingPower[currentDelegate] == 0) {
        _updateTotalCommunityVotingPower(currentDelegate, false);
    }

    // If the new delegate previously had zero voting power, then add their community VP to the totals
    if (tokenVotingPower[_delegatee] == amount) {
      _updateTotalCommunityVotingPower(_delegatee, true);
    }

    emit DelegateChanged(_delegator, currentDelegate, _delegatee);
  }

  /// @notice Updates the total community voting power totals
  /// @param _delegator The address of the user who called the function and owns the votes being delegated
  /// @param _increase Should we be increasing or decreasing the totals?
  /// @dev This function is called by _delegate, _stake, and _unstake
  function _updateTotalCommunityVotingPower(address _delegator, bool _increase) internal {
    (uint64 votes, uint64 proposalsCreated, uint64 proposalsPassed) = governance.userCommunityScoreData(_delegator);
    (uint64 totalVotes, uint64 totalProposalsCreated, uint64 totalProposalsPassed) = governance.totalCommunityScoreData();

    if (_increase) {
      governance.updateTotalCommunityScoreData(totalVotes + votes, totalProposalsCreated + proposalsCreated, totalProposalsPassed + proposalsPassed);
    } else {
      governance.updateTotalCommunityScoreData(totalVotes - votes, totalProposalsCreated - proposalsCreated, totalProposalsPassed - proposalsPassed);
    }
  }

  /////////////////////////////////
  /// STAKE & UNSTAKE FUNCTIONS ///
  /////////////////////////////////

  /// @notice Stake your tokens to get voting power
  /// @param _tokenIds An array of the id of the token you wish to stake
  /// @param _unlockTime The timestamp of the time your tokens will be unlocked
  /// @dev unlockTime can be set to 0 to stake without locking (and earn no extra staked time bonus)
  function stake(uint[] calldata _tokenIds, uint _unlockTime) public {
    // Refunds gas if stakingRefund is true and hasn't been used by this user in the past 24 hours
    if (stakingRefund && lastStakingRefund[msg.sender] + refundCooldown <= block.timestamp) {
      uint256 startGas = gasleft();
      _stake(_tokenIds, _unlockTime);
      lastStakingRefund[msg.sender] = block.timestamp;
      _refundGas(startGas);
    } else {
      _stake(_tokenIds, _unlockTime);
    }
  }

  /// @notice Internal function to stake tokens and get voting power
  /// @param _tokenIds An array of the id of the tokens being staked
  /// @param _unlockTime The timestamp of when the tokens will be unlocked
  function _stake(uint[] calldata _tokenIds, uint _unlockTime) internal {
    if (paused) revert Paused();
    if (_unlockTime > 0 && _unlockTime < block.timestamp) revert InvalidParameter();

    uint maxStakeTime = stakingSettings.maxStakeBonusTime;
    if (_unlockTime > 0 && _unlockTime - block.timestamp > maxStakeTime) {
      _unlockTime = block.timestamp + maxStakeTime;
    }

    uint numTokens = _tokenIds.length;
    // This is required to ensure the gas refunds are not abused
    if (numTokens == 0) revert InvalidParameter();
    
    uint newVotingPower;
    for (uint i = 0; i < numTokens; i++) {
        newVotingPower += _stakeToken(_tokenIds[i], _unlockTime);
    }

    votesFromOwnedTokens[msg.sender] += newVotingPower;
    tokenVotingPower[getDelegate(msg.sender)] += newVotingPower;
    totalTokenVotingPower += newVotingPower;

    // If the delegate (including self) had no tokenVotingPower before, they just unlocked their community voting power
    if (tokenVotingPower[getDelegate(msg.sender)] == newVotingPower) {
      // The delegate's community voting power is reactivated, so we add it to the total community voting power
      _updateTotalCommunityVotingPower(getDelegate(msg.sender), true);
    }
  }

  /// @notice Internal function to stake a single token and get voting power
  /// @param _tokenId The id of the token being staked
  /// @param _unlockTime The timestamp of when the token will be unlocked
  function _stakeToken(uint _tokenId, uint _unlockTime) internal returns (uint) {
    if (_unlockTime > 0) {
      unlockTime[_tokenId] = _unlockTime;
      uint fullStakedTimeBonus = ((_unlockTime - block.timestamp) * stakingSettings.maxStakeBonusAmount) / stakingSettings.maxStakeBonusTime;
      stakedTimeBonus[_tokenId] = _tokenId < 10000 ? fullStakedTimeBonus : fullStakedTimeBonus / 2;
    }

    // Transfer the underlying token from the owner to this contract
    IERC721 collection;
    if (_tokenId < 10000) {
      collection = frankenpunks;
      stakedFrankenPunks++;
    } else {
      collection = frankenmonsters;
      stakedFrankenMonsters++;
    }

    address owner = collection.ownerOf(_tokenId);
    if (msg.sender != owner) revert NotAuthorized();
    collection.transferFrom(owner, address(this), _tokenId);

    // Mint the staker a new ERC721 token representing their staked token
    _mint(msg.sender, _tokenId);

    // Return the voting power for this token based on staked time bonus and evil score
    return getTokenVotingPower(_tokenId);
  }

  /// @notice Unstake your tokens and surrender voting power
  /// @param _tokenIds An array of the ids of the tokens you wish to unstake
  /// @param _to The address to send the underlying NFT to
  function unstake(uint[] calldata _tokenIds, address _to) public {
    _unstake(_tokenIds, _to);
  }

  /// @notice Internal function to unstake tokens and surrender voting power
  /// @param _tokenIds An array of the ids of the tokens being unstaked
  /// @param _to The address to send the underlying NFT to
  function _unstake(uint[] calldata _tokenIds, address _to) internal lockedWhileVotesCast {
    uint numTokens = _tokenIds.length;
    if (numTokens == 0) revert InvalidParameter();
    
    uint lostVotingPower;
    for (uint i = 0; i < numTokens; i++) {
        lostVotingPower += _unstakeToken(_tokenIds[i], _to);
    }

    votesFromOwnedTokens[msg.sender] -= lostVotingPower;
    // Since the delegate currently has the voting power, it must be removed from their balance
    // If the user doesn't delegate, delegates(msg.sender) will return self
    tokenVotingPower[getDelegate(msg.sender)] -= lostVotingPower;
    totalTokenVotingPower -= lostVotingPower;

    // If this unstaking reduced the user or their delegate's tokenVotingPower to 0, then someone just lost their community voting power
    // First, check if the user is their own delegate
    if (msg.sender == getDelegate(msg.sender)) {
      // Did their tokenVotingPower just become 0?
      if (tokenVotingPower[msg.sender] == 0) {
        // If so, reduce the total voting power to capture this decrease in the user's community voting power
        _updateTotalCommunityVotingPower(msg.sender, false);
      }
    // If they aren't their own delegate...
    } else {
      // If their delegate's tokenVotingPower reaches 0, that means they were the final unstake and the delegate loses community voting power
      if (tokenVotingPower[getDelegate(msg.sender)] == 0) {
        // The delegate's community voting power is forfeited, so we adjust total community power balances down
        _updateTotalCommunityVotingPower(getDelegate(msg.sender), false);
      }
    }
  }

  /// @notice Internal function to unstake a single token and surrender voting power
  /// @param _tokenId The id of the token being unstaked
  /// @param _to The address to send the underlying NFT to
  function _unstakeToken(uint _tokenId, address _to) internal returns(uint) {
    address owner = ownerOf(_tokenId);
    if (msg.sender != owner) revert NotAuthorized();
    if (unlockTime[_tokenId] > block.timestamp) revert TokenLocked();
    
    // Transfer the underlying token from the owner to this contract
    IERC721 collection;
    if (_tokenId < 10000) {
      collection = frankenpunks;
      --stakedFrankenPunks;
    } else {
      collection = frankenmonsters;
      --stakedFrankenMonsters;
    }
    collection.safeTransferFrom(address(this), _to, _tokenId);

    // Voting power needs to be calculated before staked time bonus is zero'd out, as it uses this value
    uint lostVotingPower = getTokenVotingPower(_tokenId);
    _burn(_tokenId);

    if (unlockTime[_tokenId] > 0) {
      delete unlockTime[_tokenId];
      delete stakedTimeBonus[_tokenId];
    }

    return lostVotingPower;
  }

    //////////////////////////////////////////////
    ///// VOTING POWER CALCULATION FUNCTIONS /////
    //////////////////////////////////////////////
    
    /// @notice Get the total voting power (token + community) for an account
    /// @param _account The address of the account to get voting power for
    /// @return The total voting power for the account
    /// @dev This is used by governance to calculate the voting power of an account
    function getVotes(address _account) public view returns (uint) {
        return tokenVotingPower[_account] + getCommunityVotingPower(_account);
    }
    
    /// @notice Get the voting power for a specific token when staking or unstaking
    /// @param _tokenId The id of the token to get voting power for
    /// @return The voting power for the token
    /// @dev Voting power is calculated as baseVotes + staking bonus (0 to max staking bonus) + evil bonus (0 or 10)
    function getTokenVotingPower(uint _tokenId) public override view returns (uint) {
      if (ownerOf(_tokenId) == address(0)) revert NonExistentToken();

      // If tokenId < 10000, it's a FrankenPunk, so BASE_VOTES, otherwise, divide by 2 for monsters
      uint baseVotes = _tokenId < 10_000 ? BASE_VOTES : BASE_VOTES / 2;
      
      // evilBonus will return 0 for all FrankenMonsters, as they are not eligible for the evil bonus
      return baseVotes + stakedTimeBonus[_tokenId] + evilBonus(_tokenId);
    }

    /// @notice Get the community voting power for a given user
    /// @param _voter The address of the account to get community voting power for
    /// @return The community voting power the user currently has
    function getCommunityVotingPower(address _voter) public override view returns (uint) {
      uint64 votes;
      uint64 proposalsCreated;
      uint64 proposalsPassed;
      
      // We allow this function to be called with the max uint value to get the total community voting power
      if (_voter == address(type(uint160).max)) {
        (votes, proposalsCreated, proposalsPassed) = governance.totalCommunityScoreData();
      } else {
        // This is only the case if they are delegated or unstaked, both of which should zero out the result
        if (tokenVotingPower[_voter] == 0) return 0;

        (votes, proposalsCreated, proposalsPassed) = governance.userCommunityScoreData(_voter);
      }

      CommunityPowerMultipliers memory cpMultipliers = communityPowerMultipliers;

      return (
          (votes * cpMultipliers.votes) + 
          (proposalsCreated * cpMultipliers.proposalsCreated) + 
          (proposalsPassed * cpMultipliers.proposalsPassed)
        ) / PERCENT;
    }

    /// @notice Get the total voting power of the entire system
    /// @return The total votes in the system
    /// @dev This is used to calculate the quorum and proposal thresholds
    function getTotalVotingPower() public view returns (uint) {
      return totalTokenVotingPower + getCommunityVotingPower(address(type(uint160).max));
    }

    function getStakedTokenSupplies() public view returns (uint128, uint128) {
      return (stakedFrankenPunks, stakedFrankenMonsters);
    }

    /// @notice Get the evil bonus for a given token
    /// @param _tokenId The id of the token to get the evil bonus for
    /// @return The evil bonus for the token
    /// @dev The evil bonus is 10 if the token is sufficiently evil, 0 otherwise
    function evilBonus(uint _tokenId) public view returns (uint) {
      if (_tokenId >= 10000) return 0; 
      return (EVIL_BITMAPS[_tokenId >> 8] >> (255 - (_tokenId & 255)) & 1) * 10;
    }

  /////////////////////////////////
  //////// OWNER OPERATIONS ///////
  /////////////////////////////////

  /// @notice Set the max staking time needed to get the max bonus
  /// @param _newMaxStakeBonusTime The new max staking time
  /// @dev This function can only be called by the executor based on a governance proposal
  function changeStakeTime(uint128 _newMaxStakeBonusTime) external onlyExecutor {
    if (_newMaxStakeBonusTime == 0) revert InvalidParameter();
    emit StakeTimeChanged(stakingSettings.maxStakeBonusTime = _newMaxStakeBonusTime);
  }

  /// @notice Set the max staking bonus earned if a token is staked for the max time
  /// @param _newMaxStakeBonusAmount The new max staking bonus
  /// @dev This function can only be called by the executor based on a governance proposal
  function changeStakeAmount(uint128 _newMaxStakeBonusAmount) external onlyExecutor {
    emit StakeAmountChanged(stakingSettings.maxStakeBonusAmount = _newMaxStakeBonusAmount);
  }

  /// @notice Set the community power multiplier for votes
  /// @param _votesMultiplier The multiplier applied to community voting power based on past votes
  /// @dev This function can only be called by the executor based on a governance proposal
  function setVotesMultiplier(uint64 _votesMultiplier) external onlyExecutor {
    emit VotesMultiplierChanged(communityPowerMultipliers.votes = _votesMultiplier);
  }

  /// @notice Set the community power multiplier for proposals created
  /// @param _proposalsCreatedMultiplier The multiplier applied to community voting power based on proposals created
  /// @dev This function can only be called by the executor based on a governance proposal
  function setProposalsCreatedMultiplier(uint64 _proposalsCreatedMultiplier) external onlyExecutor {
    emit ProposalsCreatedMultiplierChanged(communityPowerMultipliers.proposalsCreated = _proposalsCreatedMultiplier);
  }

  /// @notice Set the community power multiplier for proposals passed
  /// @param _proposalsPassedMultiplier The multiplier applied to community voting power based on proposals passed
  /// @dev This function can only be called by the executor based on a governance proposal
  function setProposalsPassedMultiplier(uint64 _proposalsPassedMultiplier) external onlyExecutor {
    emit ProposalPassedMultiplierChanged(communityPowerMultipliers.proposalsPassed =  _proposalsPassedMultiplier);
  }

  /// @notice Turn on or off gas refunds for staking and delegating
  /// @param _stakingRefund Should refunds for staking be on (true) or off (false)?
  /// @param _delegatingRefund Should refunds for delegating be on (true) or off (false)?
  /// @param _newCooldown The amount of time a user must wait between refunds of the same type
  function setRefunds(bool _stakingRefund, bool _delegatingRefund, uint _newCooldown) external onlyExecutor {
    emit RefundSettingsChanged(
      stakingRefund = _stakingRefund, 
      delegatingRefund = _delegatingRefund,
      refundCooldown = _newCooldown
    );
  }

  /// @notice Pause or unpause staking
  /// @param _paused Whether staking should be paused or not
  /// @dev This will be used to open and close staking windows to incentivize participation
  function setPause(bool _paused) external onlyPauserOrAdmins {
    emit StakingPause(paused = _paused);
  }

  /// @notice Set hte base URI for the metadata for the staked token
  /// @param _baseURI The new base URI
  function setBaseURI(string calldata _baseURI) external onlyAdmins {
    emit BaseURIChanged(baseTokenURI = _baseURI);
  }

  /// @notice Set the contract URI for marketplace metadata
  /// @param _newContractURI The new contract URI
  function setContractURI(string calldata _newContractURI) external onlyAdmins {
    emit ContractURIChanged(contractURI = _newContractURI);
  }

  /// @notice Check to confirm that this is a FrankenPunks staking contract
  /// @dev Used by governance when upgrading staking to ensure the correct contract
  /// @dev Used instead of an interface because interface may change
  function isFrankenPunksStakingContract() external pure returns (bool) {
    return true;
  }

  /// @notice Contract can receive ETH (will be used to pay for gas refunds)
  receive() external payable {}

  /// @notice Contract can receive ETH (will be used to pay for gas refunds)
  fallback() external payable {}
}

File 2 of 13 : ERC721.sol
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;

/// @notice Modern, minimalist, and gas efficient ERC-721 implementation.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC721.sol)
abstract contract ERC721 {
    /*//////////////////////////////////////////////////////////////
                                 EVENTS
    //////////////////////////////////////////////////////////////*/

    event Transfer(address indexed from, address indexed to, uint256 indexed id);

    event Approval(address indexed owner, address indexed spender, uint256 indexed id);

    event ApprovalForAll(address indexed owner, address indexed operator, bool approved);

    /*//////////////////////////////////////////////////////////////
                         METADATA STORAGE/LOGIC
    //////////////////////////////////////////////////////////////*/

    string public name;

    string public symbol;

    function tokenURI(uint256 id) public view virtual returns (string memory);

    /*//////////////////////////////////////////////////////////////
                      ERC721 BALANCE/OWNER STORAGE
    //////////////////////////////////////////////////////////////*/

    mapping(uint256 => address) internal _ownerOf;

    mapping(address => uint256) internal _balanceOf;

    function ownerOf(uint256 id) public view virtual returns (address owner) {
        require((owner = _ownerOf[id]) != address(0), "NOT_MINTED");
    }

    function balanceOf(address owner) public view virtual returns (uint256) {
        require(owner != address(0), "ZERO_ADDRESS");

        return _balanceOf[owner];
    }

    /*//////////////////////////////////////////////////////////////
                         ERC721 APPROVAL STORAGE
    //////////////////////////////////////////////////////////////*/

    mapping(uint256 => address) public getApproved;

    mapping(address => mapping(address => bool)) public isApprovedForAll;

    /*//////////////////////////////////////////////////////////////
                               CONSTRUCTOR
    //////////////////////////////////////////////////////////////*/

    constructor(string memory _name, string memory _symbol) {
        name = _name;
        symbol = _symbol;
    }

    /*//////////////////////////////////////////////////////////////
                              ERC721 LOGIC
    //////////////////////////////////////////////////////////////*/

    function approve(address spender, uint256 id) public virtual {
        address owner = _ownerOf[id];

        require(msg.sender == owner || isApprovedForAll[owner][msg.sender], "NOT_AUTHORIZED");

        getApproved[id] = spender;

        emit Approval(owner, spender, id);
    }

    function setApprovalForAll(address operator, bool approved) public virtual {
        isApprovedForAll[msg.sender][operator] = approved;

        emit ApprovalForAll(msg.sender, operator, approved);
    }

    function transferFrom(
        address from,
        address to,
        uint256 id
    ) public virtual {
        require(from == _ownerOf[id], "WRONG_FROM");

        require(to != address(0), "INVALID_RECIPIENT");

        require(
            msg.sender == from || isApprovedForAll[from][msg.sender] || msg.sender == getApproved[id],
            "NOT_AUTHORIZED"
        );

        // Underflow of the sender's balance is impossible because we check for
        // ownership above and the recipient's balance can't realistically overflow.
        unchecked {
            _balanceOf[from]--;

            _balanceOf[to]++;
        }

        _ownerOf[id] = to;

        delete getApproved[id];

        emit Transfer(from, to, id);
    }

    function safeTransferFrom(
        address from,
        address to,
        uint256 id
    ) public virtual {
        transferFrom(from, to, id);

        require(
            to.code.length == 0 ||
                ERC721TokenReceiver(to).onERC721Received(msg.sender, from, id, "") ==
                ERC721TokenReceiver.onERC721Received.selector,
            "UNSAFE_RECIPIENT"
        );
    }

    function safeTransferFrom(
        address from,
        address to,
        uint256 id,
        bytes calldata data
    ) public virtual {
        transferFrom(from, to, id);

        require(
            to.code.length == 0 ||
                ERC721TokenReceiver(to).onERC721Received(msg.sender, from, id, data) ==
                ERC721TokenReceiver.onERC721Received.selector,
            "UNSAFE_RECIPIENT"
        );
    }

    /*//////////////////////////////////////////////////////////////
                              ERC165 LOGIC
    //////////////////////////////////////////////////////////////*/

    function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {
        return
            interfaceId == 0x01ffc9a7 || // ERC165 Interface ID for ERC165
            interfaceId == 0x80ac58cd || // ERC165 Interface ID for ERC721
            interfaceId == 0x5b5e139f; // ERC165 Interface ID for ERC721Metadata
    }

    /*//////////////////////////////////////////////////////////////
                        INTERNAL MINT/BURN LOGIC
    //////////////////////////////////////////////////////////////*/

    function _mint(address to, uint256 id) internal virtual {
        require(to != address(0), "INVALID_RECIPIENT");

        require(_ownerOf[id] == address(0), "ALREADY_MINTED");

        // Counter overflow is incredibly unrealistic.
        unchecked {
            _balanceOf[to]++;
        }

        _ownerOf[id] = to;

        emit Transfer(address(0), to, id);
    }

    function _burn(uint256 id) internal virtual {
        address owner = _ownerOf[id];

        require(owner != address(0), "NOT_MINTED");

        // Ownership check above ensures no underflow.
        unchecked {
            _balanceOf[owner]--;
        }

        delete _ownerOf[id];

        delete getApproved[id];

        emit Transfer(owner, address(0), id);
    }

    /*//////////////////////////////////////////////////////////////
                        INTERNAL SAFE MINT LOGIC
    //////////////////////////////////////////////////////////////*/

    function _safeMint(address to, uint256 id) internal virtual {
        _mint(to, id);

        require(
            to.code.length == 0 ||
                ERC721TokenReceiver(to).onERC721Received(msg.sender, address(0), id, "") ==
                ERC721TokenReceiver.onERC721Received.selector,
            "UNSAFE_RECIPIENT"
        );
    }

    function _safeMint(
        address to,
        uint256 id,
        bytes memory data
    ) internal virtual {
        _mint(to, id);

        require(
            to.code.length == 0 ||
                ERC721TokenReceiver(to).onERC721Received(msg.sender, address(0), id, data) ==
                ERC721TokenReceiver.onERC721Received.selector,
            "UNSAFE_RECIPIENT"
        );
    }
}

/// @notice A generic interface for a contract which properly accepts ERC721 tokens.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC721.sol)
abstract contract ERC721TokenReceiver {
    function onERC721Received(
        address,
        address,
        uint256,
        bytes calldata
    ) external virtual returns (bytes4) {
        return ERC721TokenReceiver.onERC721Received.selector;
    }
}

File 3 of 13 : LibString.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;

/// @notice Efficient library for creating string representations of integers.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/LibString.sol)
/// @author Modified from Solady (https://github.com/Vectorized/solady/blob/main/src/utils/LibString.sol)
library LibString {
    function toString(uint256 value) internal pure returns (string memory str) {
        assembly {
            // The maximum value of a uint256 contains 78 digits (1 byte per digit), but we allocate 160 bytes
            // to keep the free memory pointer word aligned. We'll need 1 word for the length, 1 word for the
            // trailing zeros padding, and 3 other words for a max of 78 digits. In total: 5 * 32 = 160 bytes.
            let newFreeMemoryPointer := add(mload(0x40), 160)

            // Update the free memory pointer to avoid overriding our string.
            mstore(0x40, newFreeMemoryPointer)

            // Assign str to the end of the zone of newly allocated memory.
            str := sub(newFreeMemoryPointer, 32)

            // Clean the last word of memory it may not be overwritten.
            mstore(str, 0)

            // Cache the end of the memory to calculate the length later.
            let end := str

            // We write the string from rightmost digit to leftmost digit.
            // The following is essentially a do-while loop that also handles the zero case.
            // prettier-ignore
            for { let temp := value } 1 {} {
                // Move the pointer 1 byte to the left.
                str := sub(str, 1)

                // Write the character to the pointer.
                // The ASCII index of the '0' character is 48.
                mstore8(str, add(48, mod(temp, 10)))

                // Keep dividing temp until zero.
                temp := div(temp, 10)

                 // prettier-ignore
                if iszero(temp) { break }
            }

            // Compute and cache the final total length of the string.
            let length := sub(end, str)

            // Move the pointer 32 bytes leftwards to make room for the length.
            str := sub(str, 32)

            // Store the string's length at the start of memory allocated for our string.
            mstore(str, length)
        }
    }
}

File 4 of 13 : FrankenDAOErrors.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;

contract FrankenDAOErrors {
    // General purpose
    error NotAuthorized();

    // Staking
    error NonExistentToken();
    error InvalidDelegation();
    error Paused();
    error InvalidParameter();
    error TokenLocked();
    error StakedTokensCannotBeTransferred();

    // Governance
    error ZeroAddress();
    error AlreadyInitialized();
    error ParameterOutOfBounds();
    error InvalidId();
    error InvalidProposal();
    error InvalidStatus();
    error InvalidInput();
    error AlreadyVoted();
    error NotEligible();
    error NotInActiveProposals();
    error NotStakingContract();

    // Executor
    error DelayNotSatisfied();
    error IdenticalTransactionAlreadyQueued();
    error TransactionNotQueued();
    error TimelockNotMet();
    error TransactionReverted();
}

File 5 of 13 : IAdmin.sol
pragma solidity ^0.8.10;

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

interface IAdmin {

    ////////////////////
    ////// Events //////
    ////////////////////

    /// @notice Emited when a new address is set for the Council
    event NewCouncil(address oldCouncil, address newCouncil);
    /// @notice Emited when a new address is set for the Founders
    event NewFounders(address oldFounders, address newFounders);
    /// @notice Emited when a new address is set for the Pauser
    event NewPauser(address oldPauser, address newPauser);
    /// @notice Emited when a new address is set for the Verifier
    event NewVerifier(address oldVerifier, address newVerifier);
    /// @notice Emitted when pendingFounders is changed
    event NewPendingFounders(address oldPendingFounders, address newPendingFounders);

    /////////////////////
    ////// Methods //////
    /////////////////////

    function acceptFounders() external;
    function council() external view returns (address);
    function executor() external view returns (IExecutor);
    function founders() external view returns (address);
    function pauser() external view returns (address);
    function pendingFounders() external view returns (address);
    function revokeFounders() external;
    function setCouncil(address _newCouncil) external;
    function setPauser(address _newPauser) external;
    function setPendingFounders(address _newPendingFounders) external;
}

File 6 of 13 : IERC721.sol
pragma solidity ^0.8.13;

interface IERC721 {
    function approve(address spender, uint id) external;
    function transferFrom(address from, address to, uint256 tokenId) external;
    function safeTransferFrom(address from, address to, uint256 tokenId) external;
    function ownerOf(uint256 tokenId) external view returns (address);
    function balanceOf(address owner) external view returns (uint256);
    function isApprovedForAll(address owner, address operator) external view returns (bool);
    function getApproved(uint256 tokenId) external view returns (address);
}

File 7 of 13 : IExecutor.sol
pragma solidity ^0.8.10;

interface IExecutor {

    ////////////////////
    ////// Events //////
    ////////////////////

    /// @notice Emited when a transaction is cancelled
    event CancelTransaction(bytes32 indexed txHash, uint256 id, address indexed target, uint256 value, string signature, bytes data, uint256 eta);
    /// @notice Emited when a transaction is executed
    event ExecuteTransaction(bytes32 indexed txHash, uint256 id, address indexed target, uint256 value, string signature, bytes data, uint256 eta);
    /// @notice Emited when a new delay value is set
    event NewDelay(uint256 indexed newDelay);
    /// @notice Emited when a transaction is queued
    event QueueTransaction(bytes32 indexed txHash, uint256 id, address indexed target, uint256 value, string signature, bytes data, uint256 eta);

    /////////////////////
    ////// Methods //////
    /////////////////////

    function DELAY() external view returns (uint256);

    function GRACE_PERIOD() external view returns (uint256);

    function cancelTransaction(uint256 _id, address _target, uint256 _value, string memory _signature, bytes memory _data, uint256 _eta) external;

    function executeTransaction(uint256 _id, address _target, uint256 _value, string memory _signature, bytes memory _data, uint256 _eta) external returns (bytes memory);

    function queueTransaction(uint256 _id, address _target, uint256 _value, string memory _signature, bytes memory _data, uint256 _eta) external returns (bytes32 txHash);

    function queuedTransactions(bytes32) external view returns (bool);
}

File 8 of 13 : IGovernance.sol
pragma solidity ^0.8.10;

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

interface IGovernance {

    ////////////////////
    ////// Events //////
    ////////////////////

    /// @notice Emited when a proposal is canceled
    event ProposalCanceled(uint256 id);
    /// @notice Emited when a proposal is created
    event ProposalCreated( uint256 id, address proposer, address[] targets, uint256[] values, string[] signatures, bytes[] calldatas, uint32 startTime, uint32 endTime, uint24 quorumVotes, string description);
    /// @notice Emited when a proposal is executed
    event ProposalExecuted(uint256 id);
    /// @notice Emited when a proposal is queued
    event ProposalQueued(uint256 id, uint256 eta);
    /// @notice Emited when a proposal is vetoed
    event ProposalVetoed(uint256 id);
    /// @notice Emited when a new proposal threshold BPS is set
    event ProposalThresholdBPSSet(uint256 oldProposalThresholdBPS, uint256 newProposalThresholdBPS);
    /// @notice Emited when a new quorum votes BPS is set
    event QuorumVotesBPSSet(uint256 oldQuorumVotesBPS, uint256 newQuorumVotesBPS);
    /// @notice Emited when the refund status changes
    event RefundSet(bool isProposingRefund, bool oldStatus, bool newStatus);
    /// @notice Emited when the total community score data is updated
    event TotalCommunityScoreDataUpdated(uint64 proposalsCreated, uint64 proposalsPassed, uint64 votes);
    /// @notice Emited when a vote is cast
    event VoteCast(address indexed voter, uint256 proposalId, uint8 support, uint256 votes);
    /// @notice Emited when the voting delay is updated
    event VotingDelaySet(uint256 oldVotingDelay, uint256 newVotingDelay);
    /// @notice Emited when the voting period is updated
    event VotingPeriodSet(uint256 oldVotingPeriod, uint256 newVotingPeriod);
    /// @notice Emited when the staking contract is changed.
    event NewStakingContract(address stakingContract);

    /////////////////////
    ////// Storage //////
    /////////////////////

    struct CommunityScoreData {
        uint64 votes;
        uint64 proposalsCreated;
        uint64 proposalsPassed;
    }

    struct Proposal {
        /// @notice Unique id for looking up a proposal
        uint96 id;
        /// @notice Creator of the proposal
        address proposer;
        /// @notice the ordered list of target addresses for calls to be made
        address[] targets;
        /// @notice The ordered list of values (i.e. msg.value) to be passed to the calls to be made
        uint256[] values;
        /// @notice The ordered list of function signatures to be called
        string[] signatures;
        /// @notice The ordered list of calldata to be passed to each call
        bytes[] calldatas;
        /// @notice The number of votes in support of a proposal required in order for a quorum to be reached and for a vote to succeed at the time of proposal creation. 
        uint24 quorumVotes;
        /// @notice The timestamp that the proposal will be available for execution, set once the vote succeeds
        uint32 eta;
        /// @notice The block at which voting begins: holders must delegate their votes prior to this block
        uint32 startTime;
        /// @notice The block at which voting ends: votes must be cast prior to this block
        uint32 endTime;
        /// @notice Current number of votes in favor of this proposal
        uint24 forVotes;
        /// @notice Current number of votes in opposition to this proposal
        uint24 againstVotes;
        /// @notice Current number of votes for abstaining for this proposal
        uint24 abstainVotes;
        /// @notice Flag marking whether a proposal has been verified
        bool verified;
        /// @notice Flag marking whether the proposal has been canceled
        bool canceled;
        /// @notice Flag marking whether the proposal has been vetoed
        bool vetoed;
        /// @notice Flag marking whether the proposal has been executed
        bool executed;
        /// @notice Receipts of ballots for the entire set of voters
        mapping(address => Receipt) receipts;
    }

    /// @notice Ballot receipt record for a voter
    struct Receipt {
        /// @notice Whether or not a vote has been cast
        bool hasVoted;
        /// @notice Whether or not the voter supports the proposal or abstains
        uint8 support;
        /// @notice The number of votes the voter had, which were cast
        uint24 votes;
    }

    /// @notice Possible states that a proposal may be in
    enum ProposalState {
        Pending,
        Active,
        Canceled,
        Defeated,
        Succeeded,
        Queued,
        Expired,
        Executed,
        Vetoed
    }

    /////////////////////
    ////// Methods //////
    /////////////////////

    function MAX_PROPOSAL_THRESHOLD_BPS() external view returns (uint256);
    function MAX_QUORUM_VOTES_BPS() external view returns (uint256);
    function MAX_VOTING_DELAY() external view returns (uint256);
    function MAX_VOTING_PERIOD() external view returns (uint256);
    function MIN_PROPOSAL_THRESHOLD_BPS() external view returns (uint256);
    function MIN_QUORUM_VOTES_BPS() external view returns (uint256);
    function MIN_VOTING_DELAY() external view returns (uint256);
    function MIN_VOTING_PERIOD() external view returns (uint256);
    function PROPOSAL_MAX_OPERATIONS() external view returns (uint256);
    function activeProposals(uint256) external view returns (uint256);
    function cancel(uint256 _proposalId) external;
    function castVote(uint256 _proposalId, uint8 _support) external;
    function clear(uint256 _proposalId) external;
    function execute(uint256 _proposalId) external;
    function getActions(uint256 _proposalId)
        external
        view
        returns (
            address[] memory targets,
            uint256[] memory values,
            string[] memory signatures,
            bytes[] memory calldatas
        );
    function getActiveProposals() external view returns (uint256[] memory);
    function getProposalData(uint256 _proposalId) external view returns (uint256, address, uint256);
    function getProposalStatus(uint256 _proposalId) external view returns (bool, bool, bool, bool);
    function getProposalVotes(uint256 _proposalId) external view returns (uint256, uint256, uint256);
    function getReceipt(uint256 _proposalId, address _voter) external view returns (Receipt memory);
    function initialize(
        address _staking,
        address _executor,
        address _founders,
        address _council,
        uint256 _votingPeriod,
        uint256 _votingDelay,
        uint256 _proposalThresholdBPS,
        uint256 _quorumVotesBPS
    ) external;
    function latestProposalIds(address) external view returns (uint256);
    function name() external view returns (string memory);
    function proposalCount() external view returns (uint256);
    function proposalRefund() external view returns (bool);
    function proposalThreshold() external view returns (uint256);
    function proposalThresholdBPS() external view returns (uint256);
    function proposals(uint256)
        external
        view
        returns (
            uint96 id,
            address proposer,
            uint24 quorumVotes,
            uint32 eta,
            uint32 startTime,
            uint32 endTime,
            uint24 forVotes,
            uint24 againstVotes,
            uint24 abstainVotes,
            bool verified,
            bool canceled,
            bool vetoed,
            bool executed
        );
    function propose(
        address[] memory _targets,
        uint256[] memory _values,
        string[] memory _signatures,
        bytes[] memory _calldatas,
        string memory _description
    ) external returns (uint256);
    function queue(uint256 _proposalId) external;
    function quorumVotes() external view returns (uint256);
    function quorumVotesBPS() external view returns (uint256);
    function setProposalThresholdBPS(uint256 _newProposalThresholdBPS) external;
    function setQuorumVotesBPS(uint256 _newQuorumVotesBPS) external;
    function setRefunds(bool _votingRefund, bool _proposalRefund) external;
    function setStakingAddress(IStaking _newStaking) external;
    function setVotingDelay(uint256 _newVotingDelay) external;
    function setVotingPeriod(uint256 _newVotingPeriod) external;
    function staking() external view returns (IStaking);
    function state(uint256 _proposalId) external view returns (ProposalState);
    function totalCommunityScoreData()
        external
        view
        returns (uint64 votes, uint64 proposalsCreated, uint64 proposalsPassed);
    function updateTotalCommunityScoreData(uint64 _votes, uint64 _proposalsCreated, uint64 _proposalsPassed) external;
    function userCommunityScoreData(address)
        external
        view
        returns (uint64 votes, uint64 proposalsCreated, uint64 proposalsPassed);
    function verifyProposal(uint256 _proposalId) external;
    function veto(uint256 _proposalId) external;
    function votingDelay() external view returns (uint256);
    function votingPeriod() external view returns (uint256);
    function votingRefund() external view returns (bool);
}

File 9 of 13 : IRefundable.sol
pragma solidity ^0.8.10;

interface IRefundable {

    ////////////////////
    ////// Events //////
    ////////////////////

    /// @notice Emitted when a refund is issued
    event IssueRefund(address refunded, uint256 amount, bool sent, uint256 remainingBalance);

    /// @notice Emited when we're not able to refund the full amount
    event InsufficientFundsForRefund(address refunded, uint256 intendedAmount, uint256 sentAmount);

    /////////////////////
    ////// Methods //////
    /////////////////////

    function MAX_REFUND_PRIORITY_FEE() external view returns (uint256);
    function REFUND_BASE_GAS() external view returns (uint256);
}

File 10 of 13 : IStaking.sol
pragma solidity ^0.8.10;

interface IStaking {

    ////////////////////
    ////// Events //////
    ////////////////////

    /// @notice Emited a staker changes who they're delegating to
    event DelegateChanged(address indexed delegator, address indexed fromDelegate, address indexed toDelegate);
    /// @notice Emited when staking is paused/unpaused
    event StakingPause(bool status);
    /// @notice Emited when admins change the token's base URI
    event BaseURIChanged(string _baseURI);
    /// @notice Emited when the contract URI is updated
    event ContractURIChanged(string _contractURI);
    /// @notice Emited when refund settings are updated
    event RefundSettingsChanged(bool _stakingRefund, bool _delegatingRefund, uint256 _newCooldown);
    /// @notice Emited when FrankenMonster voting multiplier is changed
    event MonsterMultiplierChanged(uint256 _monsterMultiplier);
    /// @notice Emited when the voting multiplier for passed proposals is changed
    event ProposalPassedMultiplierChanged(uint64 _proposalPassedMultiplier);
    /// @notice Emited when the stake time multiplier is changed
    event StakeTimeChanged(uint128 _stakeTime);
    /// @notice Emited when the staking multiplier is changed
    event StakeAmountChanged(uint128 _stakeAmount);
    /// @notice Emited when the voting multiplier for voting is changed
    event VotesMultiplierChanged(uint64 _votesMultiplier);
    /// @notice Emited when the voting multiplier for creating proposals is changed
    event ProposalsCreatedMultiplierChanged(uint64 _proposalsCreatedMultiplier);
    /// @notice Emited when the base votes for a token is changed
    event BaseVotesChanged(uint256 _baseVotes);

    /////////////////////
    ////// Storage //////
    /////////////////////

    struct CommunityPowerMultipliers {
        uint64 votes;
        uint64 proposalsCreated;
        uint64 proposalsPassed;
    }

    struct StakingSettings {
        uint128 maxStakeBonusTime;
        uint128 maxStakeBonusAmount;
    }

    enum RefundStatus { 
        StakingAndDelegatingRefund,
        StakingRefund, 
        DelegatingRefund, 
        NoRefunds
    }

    /////////////////////
    ////// Methods //////
    /////////////////////

    function baseTokenURI() external view returns (string memory);
    function BASE_VOTES() external view returns (uint256);
    function changeStakeAmount(uint128 _newMaxStakeBonusAmount) external;
    function changeStakeTime(uint128 _newMaxStakeBonusTime) external;
    function communityPowerMultipliers()
        external
        view
        returns (uint64 votes, uint64 proposalsCreated, uint64 proposalsPassed);
    function delegate(address _delegatee) external;
    function delegatingRefund() external view returns (bool);
    function evilBonus(uint256 _tokenId) external view returns (uint256);
    function getCommunityVotingPower(address _voter) external view returns (uint256);
    function getDelegate(address _delegator) external view returns (address);
    function getStakedTokenSupplies() external view returns (uint128, uint128);
    function getTokenVotingPower(uint256 _tokenId) external view returns (uint256);
    function getTotalVotingPower() external view returns (uint256);
    function getVotes(address _account) external view returns (uint256);
    function isFrankenPunksStakingContract() external pure returns (bool);
    function lastDelegatingRefund(address) external view returns (uint256);
    function lastStakingRefund(address) external view returns (uint256);
    function paused() external view returns (bool);
    function setBaseURI(string memory _baseURI) external;
    function setPause(bool _paused) external;
    function setProposalsCreatedMultiplier(uint64 _proposalsCreatedMultiplier) external;
    function setProposalsPassedMultiplier(uint64 _proposalsPassedMultiplier) external;
    function setRefunds(bool _stakingRefund, bool _delegatingRefund, uint256 _newCooldown) external;
    function setVotesMultiplier(uint64 _votesmultiplier) external;
    function stake(uint256[] memory _tokenIds, uint256 _unlockTime) external;
    function stakedFrankenMonsters() external view returns (uint128);
    function stakedFrankenPunks() external view returns (uint128);
    function stakingRefund() external view returns (bool);
    function stakingSettings() external view returns (uint128 maxStakeBonusTime, uint128 maxStakeBonusAmount);
    function tokenVotingPower(address) external view returns (uint256);
    function unlockTime(uint256) external view returns (uint256);
    function unstake(uint256[] memory _tokenIds, address _to) external;
    function votesFromOwnedTokens(address) external view returns (uint256);
}

File 11 of 13 : Admin.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;

import "../interfaces/IAdmin.sol";
import "../interfaces/IExecutor.sol";
import { FrankenDAOErrors } from "../errors/FrankenDAOErrors.sol";

/// @notice Custom access control manager for FrankenDAO
/// @dev This functionality is inherited by Governance.sol and Staking.sol
abstract contract Admin is IAdmin, FrankenDAOErrors {
    /// @notice Founder multisig
    address public founders;

    /// @notice Council multisig
    address public council;

    /// @notice Executor contract address for passed governance proposals
    IExecutor public executor;

    /// @notice Admin that only has the power to pause and unpause staking
    /// @dev This will be a EOA used by the team for easy pausing and unpausing
    /// @dev This address is changeable by governance if the community thinks the team is misusing this power
    address public pauser;

    /// @notice Admin that only has the power to verify contracts
    /// @dev This will be an EOA used by the team for contract verification
    address public verifier;

    /// @notice Pending founder addresses for this contract
    /// @dev Only founders is two-step, because errors in transferring other admin addresses can be corrected by founders
    address public pendingFounders;

    /////////////////////////////
    ///////// MODIFIERS /////////
    /////////////////////////////

    /// @notice Modifier for functions that can only be called by the Executor contract
    /// @dev This is for functions that only Governance is able to call
    modifier onlyExecutor() {
        if(msg.sender != address(executor)) revert NotAuthorized();
        _;
    }

    /// @notice Modifier for functions that can only be called by the Council or Founder multisigs
    modifier onlyAdmins() {
        if(msg.sender != founders && msg.sender != council) revert NotAuthorized();
        _;
    }

    /// @notice Modifier for functions that can only be called by the Pauser or either multisig
    modifier onlyPauserOrAdmins() {
        if(msg.sender != founders && msg.sender != council && msg.sender != pauser) revert NotAuthorized();
        _;
    }

    modifier onlyVerifierOrAdmins() {
        if(msg.sender != founders && msg.sender != council && msg.sender != verifier) revert NotAuthorized();
        _;
    }

    /// @notice Modifier for functions that can only be called by either multisig or the Executor contract
    modifier onlyExecutorOrAdmins() {
        if (
            msg.sender != address(executor) && 
            msg.sender != council && 
            msg.sender != founders
        ) revert NotAuthorized();
        _;
    }

    /////////////////////////////
    ////// ADMIN TRANSFERS //////
    /////////////////////////////

    /// @notice Begins transfer of founder rights. The newPendingFounders must call `_acceptFounders` to finalize the transfer.
    /// @param _newPendingFounders New pending founder.
    /// @dev This doesn't use onlyAdmins because only Founders have the right to set new Founders.
    function setPendingFounders(address _newPendingFounders) external {
        if (msg.sender != founders) revert NotAuthorized();
        emit NewPendingFounders(pendingFounders, _newPendingFounders);
        pendingFounders = _newPendingFounders;
    }

    /// @notice Accepts transfer of founder rights. msg.sender must be pendingFounders
    function acceptFounders() external {
        if (msg.sender != pendingFounders) revert NotAuthorized();
        emit NewFounders(founders, pendingFounders);
        founders = pendingFounders;
        pendingFounders = address(0);
    }

    /// @notice Revokes permissions for the founder multisig
    /// @dev Only the founders can call this, as nobody else should be able to revoke this permission
    /// @dev Used for eventual decentralization, as otherwise founders cannot be set to address(0) because of two-step
    /// @dev This also ensures that pendingFounders is set to address(0), to ensure they can't re-accept it later
    function revokeFounders() external {
        if (msg.sender != founders) revert NotAuthorized();
        
        emit NewFounders(founders, address(0));
        
        founders = address(0);
        pendingFounders = address(0);
    }

    /// @notice Transfers council address to a new multisig
    /// @param _newCouncil New address for council
    /// @dev This uses onlyAdmin because either the Council or the Founders can set a new Council.
    function setCouncil(address _newCouncil) external onlyAdmins {
       
        emit NewCouncil(council, _newCouncil);
       
        council = _newCouncil;
    }

    /// @notice Transfers verifier role to a new address.
    /// @param _newVerifier New address for verifier
    function setVerifier(address _newVerifier) external onlyAdmins {

        emit NewVerifier(verifier, _newVerifier);
        
        verifier = _newVerifier;
    }

    /// @notice Transfers pauser role to a new address.
    /// @param _newPauser New address for pauser
    function setPauser(address _newPauser) external onlyExecutorOrAdmins {
        
        emit NewPauser(pauser, _newPauser);
        
        pauser = _newPauser;
    }
}

File 12 of 13 : Refundable.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;

import "../interfaces/IRefundable.sol";
import { FrankenDAOErrors } from "../errors/FrankenDAOErrors.sol";

/// @notice Provides a _refundGas() function that can be used for inhering contracts to refund user gas cost
/// @dev This functionality is inherited by Governance.sol (for proposing and voting) and Staking.sol (for staking and delegating)
contract Refundable is IRefundable, FrankenDAOErrors {

    /// @notice The maximum priority fee used to cap gas refunds
    uint256 public constant MAX_REFUND_PRIORITY_FEE = 2 gwei;

    /// @notice Gas used before _startGas or after refund
    /// @dev Includes 21K TX base, 3.7K for other overhead, and 2.3K for ETH transfer 
    /** @dev This will be slightly different depending on which function is used, but all are within a few 
        thousand gas, so approximation is fine. */
    uint256 public constant REFUND_BASE_GAS = 27_000;

    /// @notice Calculate the amount spent on gas and send that to msg.sender from the contract's balance
    /// @param _startGas gasleft() at the start of the transaction, used to calculate gas spent
    /// @dev Forked from NounsDAO: https://github.com/nounsDAO/nouns-monorepo/blob/master/packages/nouns-contracts/contracts/governance/NounsDAOLogicV2.sol#L1033-L1046
    function _refundGas(uint256 _startGas) internal {
        unchecked {
            uint256 gasPrice = _min(tx.gasprice, block.basefee + MAX_REFUND_PRIORITY_FEE);
            uint256 gasUsed = _startGas - gasleft() + REFUND_BASE_GAS;
            uint refundAmount = gasPrice * gasUsed;
            
            // If gas fund runs out, pay out as much as possible and emit warning event.
            if (address(this).balance < refundAmount) {
                emit InsufficientFundsForRefund(msg.sender, refundAmount, address(this).balance);
                refundAmount = address(this).balance;
            }

            // There shouldn't be any reentrancy risk, as this is called last at all times.
            // They also can't exploit the refund by wasting gas before we've already finalized amount.
            (bool refundSent, ) = msg.sender.call{ value: refundAmount }('');

            // Includes current balance in event so team can listen and filter to know when to propose refill.
            emit IssueRefund(msg.sender, refundAmount, refundSent, address(this).balance);
        }
    }

    /// @notice Returns the lower value of two uints
    /// @param a First uint
    /// @param b Second uint
    function _min(uint256 a, uint256 b) internal pure returns (uint256) {
        return a < b ? a : b;
    }
}

File 13 of 13 : SafeCast.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (utils/math/SafeCast.sol)
// This file was procedurally generated from scripts/generate/templates/SafeCast.js.

pragma solidity ^0.8.0;

/**
 * @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow
 * checks.
 *
 * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can
 * easily result in undesired exploitation or bugs, since developers usually
 * assume that overflows raise errors. `SafeCast` restores this intuition by
 * reverting the transaction when such an operation overflows.
 *
 * Using this library instead of the unchecked operations eliminates an entire
 * class of bugs, so it's recommended to use it always.
 *
 * Can be combined with {SafeMath} and {SignedSafeMath} to extend it to smaller types, by performing
 * all math on `uint256` and `int256` and then downcasting.
 */
library SafeCast {
    /**
     * @dev Returns the downcasted uint96 from uint256, reverting on
     * overflow (when the input is greater than largest uint96).
     *
     * Counterpart to Solidity's `uint96` operator.
     *
     * Requirements:
     *
     * - input must fit into 96 bits
     *
     * _Available since v4.2._
     */
    function toUint96(uint256 value) internal pure returns (uint96) {
        require(value <= type(uint96).max, "SafeCast: value doesn't fit in 96 bits");
        return uint96(value);
    }

    /**
     * @dev Returns the downcasted uint32 from uint256, reverting on
     * overflow (when the input is greater than largest uint32).
     *
     * Counterpart to Solidity's `uint32` operator.
     *
     * Requirements:
     *
     * - input must fit into 32 bits
     *
     * _Available since v2.5._
     */
    function toUint32(uint256 value) internal pure returns (uint32) {
        require(value <= type(uint32).max, "SafeCast: value doesn't fit in 32 bits");
        return uint32(value);
    }

    /**
     * @dev Returns the downcasted uint24 from uint256, reverting on
     * overflow (when the input is greater than largest uint24).
     *
     * Counterpart to Solidity's `uint24` operator.
     *
     * Requirements:
     *
     * - input must fit into 24 bits
     *
     * _Available since v4.7._
     */
    function toUint24(uint256 value) internal pure returns (uint24) {
        require(value <= type(uint24).max, "SafeCast: value doesn't fit in 24 bits");
        return uint24(value);
    }
}

Settings
{
  "remappings": [
    "@openzeppelin/=lib/openzeppelin-contracts/contracts/",
    "ds-test/=lib/solmate/lib/ds-test/src/",
    "forge-std/=lib/forge-std/src/",
    "solmate/=lib/solmate/src/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "metadata": {
    "bytecodeHash": "ipfs"
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "london",
  "libraries": {}
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address","name":"_frankenpunks","type":"address"},{"internalType":"address","name":"_frankenmonsters","type":"address"},{"internalType":"address","name":"_governance","type":"address"},{"internalType":"address","name":"_executor","type":"address"},{"internalType":"address","name":"_founders","type":"address"},{"internalType":"address","name":"_council","type":"address"},{"internalType":"string","name":"_baseTokenURI","type":"string"},{"internalType":"string","name":"_contractURI","type":"string"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AlreadyInitialized","type":"error"},{"inputs":[],"name":"AlreadyVoted","type":"error"},{"inputs":[],"name":"DelayNotSatisfied","type":"error"},{"inputs":[],"name":"IdenticalTransactionAlreadyQueued","type":"error"},{"inputs":[],"name":"InvalidDelegation","type":"error"},{"inputs":[],"name":"InvalidId","type":"error"},{"inputs":[],"name":"InvalidInput","type":"error"},{"inputs":[],"name":"InvalidParameter","type":"error"},{"inputs":[],"name":"InvalidProposal","type":"error"},{"inputs":[],"name":"InvalidStatus","type":"error"},{"inputs":[],"name":"NonExistentToken","type":"error"},{"inputs":[],"name":"NotAuthorized","type":"error"},{"inputs":[],"name":"NotEligible","type":"error"},{"inputs":[],"name":"NotInActiveProposals","type":"error"},{"inputs":[],"name":"NotStakingContract","type":"error"},{"inputs":[],"name":"ParameterOutOfBounds","type":"error"},{"inputs":[],"name":"Paused","type":"error"},{"inputs":[],"name":"StakedTokensCannotBeTransferred","type":"error"},{"inputs":[],"name":"TimelockNotMet","type":"error"},{"inputs":[],"name":"TokenLocked","type":"error"},{"inputs":[],"name":"TransactionNotQueued","type":"error"},{"inputs":[],"name":"TransactionReverted","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"_baseURI","type":"string"}],"name":"BaseURIChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_baseVotes","type":"uint256"}],"name":"BaseVotesChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"_contractURI","type":"string"}],"name":"ContractURIChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"delegator","type":"address"},{"indexed":true,"internalType":"address","name":"fromDelegate","type":"address"},{"indexed":true,"internalType":"address","name":"toDelegate","type":"address"}],"name":"DelegateChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"refunded","type":"address"},{"indexed":false,"internalType":"uint256","name":"intendedAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"sentAmount","type":"uint256"}],"name":"InsufficientFundsForRefund","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"refunded","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"bool","name":"sent","type":"bool"},{"indexed":false,"internalType":"uint256","name":"remainingBalance","type":"uint256"}],"name":"IssueRefund","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_monsterMultiplier","type":"uint256"}],"name":"MonsterMultiplierChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldCouncil","type":"address"},{"indexed":false,"internalType":"address","name":"newCouncil","type":"address"}],"name":"NewCouncil","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldFounders","type":"address"},{"indexed":false,"internalType":"address","name":"newFounders","type":"address"}],"name":"NewFounders","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldPauser","type":"address"},{"indexed":false,"internalType":"address","name":"newPauser","type":"address"}],"name":"NewPauser","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldPendingFounders","type":"address"},{"indexed":false,"internalType":"address","name":"newPendingFounders","type":"address"}],"name":"NewPendingFounders","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldVerifier","type":"address"},{"indexed":false,"internalType":"address","name":"newVerifier","type":"address"}],"name":"NewVerifier","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"_proposalPassedMultiplier","type":"uint64"}],"name":"ProposalPassedMultiplierChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"_proposalsCreatedMultiplier","type":"uint64"}],"name":"ProposalsCreatedMultiplierChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"_stakingRefund","type":"bool"},{"indexed":false,"internalType":"bool","name":"_delegatingRefund","type":"bool"},{"indexed":false,"internalType":"uint256","name":"_newCooldown","type":"uint256"}],"name":"RefundSettingsChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint128","name":"_stakeAmount","type":"uint128"}],"name":"StakeAmountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint128","name":"_stakeTime","type":"uint128"}],"name":"StakeTimeChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"status","type":"bool"}],"name":"StakingPause","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"_votesMultiplier","type":"uint64"}],"name":"VotesMultiplierChanged","type":"event"},{"stateMutability":"payable","type":"fallback"},{"inputs":[],"name":"BASE_VOTES","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_REFUND_PRIORITY_FEE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REFUND_BASE_GAS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"acceptFounders","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"baseTokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint128","name":"_newMaxStakeBonusAmount","type":"uint128"}],"name":"changeStakeAmount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint128","name":"_newMaxStakeBonusTime","type":"uint128"}],"name":"changeStakeTime","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"communityPowerMultipliers","outputs":[{"internalType":"uint64","name":"votes","type":"uint64"},{"internalType":"uint64","name":"proposalsCreated","type":"uint64"},{"internalType":"uint64","name":"proposalsPassed","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"contractURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"council","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_delegatee","type":"address"}],"name":"delegate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"delegatingRefund","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"evilBonus","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"executor","outputs":[{"internalType":"contract IExecutor","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"founders","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_voter","type":"address"}],"name":"getCommunityVotingPower","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_delegator","type":"address"}],"name":"getDelegate","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getStakedTokenSupplies","outputs":[{"internalType":"uint128","name":"","type":"uint128"},{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"getTokenVotingPower","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTotalVotingPower","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"getVotes","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isFrankenPunksStakingContract","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"lastDelegatingRefund","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"lastStakingRefund","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"owner","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pauser","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingFounders","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"refundCooldown","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"revokeFounders","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_baseURI","type":"string"}],"name":"setBaseURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_newContractURI","type":"string"}],"name":"setContractURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newCouncil","type":"address"}],"name":"setCouncil","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_paused","type":"bool"}],"name":"setPause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newPauser","type":"address"}],"name":"setPauser","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newPendingFounders","type":"address"}],"name":"setPendingFounders","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"_proposalsCreatedMultiplier","type":"uint64"}],"name":"setProposalsCreatedMultiplier","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"_proposalsPassedMultiplier","type":"uint64"}],"name":"setProposalsPassedMultiplier","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_stakingRefund","type":"bool"},{"internalType":"bool","name":"_delegatingRefund","type":"bool"},{"internalType":"uint256","name":"_newCooldown","type":"uint256"}],"name":"setRefunds","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newVerifier","type":"address"}],"name":"setVerifier","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"_votesMultiplier","type":"uint64"}],"name":"setVotesMultiplier","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_tokenIds","type":"uint256[]"},{"internalType":"uint256","name":"_unlockTime","type":"uint256"}],"name":"stake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"stakedFrankenMonsters","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"stakedFrankenPunks","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"stakingRefund","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"stakingSettings","outputs":[{"internalType":"uint128","name":"maxStakeBonusTime","type":"uint128"},{"internalType":"uint128","name":"maxStakeBonusAmount","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"tokenVotingPower","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"unlockTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_tokenIds","type":"uint256[]"},{"internalType":"address","name":"_to","type":"address"}],"name":"unstake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"verifier","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"votesFromOwnedTokens","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]

6105806040527d80001100000000000008002002000080008000400000400020000000100060809081527f200800300200000000600000000000030000000000000000000000000008000060a05279180000000000088000000000000000000000040008000200000060c0527b0100000000000000000000000000000012090000000900000000000060e0527f2000000000000000000000000000000001000000000100000000000000002000610100527f0800000000400400000000002000000000000080080000000000000000040001610120527d400000100010000000010000004000000000000200800000000000000000610140527d010000010100000000000020000020000200000000000000000000000008610160527d800000001000100003080025000800000000080000010000050000000000610180527f20000000040100210000000000000000008000020000000000000000000000006101a0527c04000000000800000000002000000000000003000004000000000000006101c0527f02000000210000002000000000000000000120000000140000000000000030106101e0527d20002000000000800008000000000000000000000000010001040004000061020052618001607d1b610220527720000000000040000000006000000004000a000000101001610240527c040000000000000000000000100208004008000000110000000040000061026052792000200000000000008000000000000000000000004100000020610280527a1000000000000000200000000000000000000000001000200010006102a0527340100000000000008008000000008000000040006102c0527d4080000020000000000004000000000000000820000000000000000000006102e0527d010140000000000008000000000000000100000000040004000102000008610300527f0100000000000000000080000000020100000000000000100002000008020000610320527920000040800000000000000000002000000000000000000000206103405274020000000000000800000000100000000000002000610360527c0800000000000000000000400000020000000000000000001001000000610380527c01000000000000000000000000104100000000800400020000002000206103a0527f08400004000010108800000800040000001000000000000200000100000000006103c0527a5120000000000000000010000000000001000000000000000002006103e0527f4000000000004000000810000010000000010000400000000800000000004004610400527d080000800000002080000000000000000000800002000000000400000800610420527d08000001000000000800000000002000000000000000000002010008010161044052780800000000080000040008000000880120120008002000000061046052730800000000020000000000000000008000000080610480527c10000000000000400000000200000000000000000000000020000000006104a0527b400420000000000040084000020800200020100000000000000000006104c0527b040000000000110000000000000000402000000000000000040000006104e0527c0200000000020000004000000001000001021000000000000000020000610500527840004000004000000208080200000004100000100400100000610520527d200000000001000000000000000000000800000000000400000000000000610540526000610560526200051a906020906028620006da565b503480156200052857600080fd5b50604051620046a9380380620046a98339810160408190526200054b9162000816565b6040518060400160405280601381526020017f5374616b6564204672616e6b656e50756e6b73000000000000000000000000008152506040518060400160405280600381526020016207346560ec1b8152508160009081620005ae919062000980565b506001620005bd828262000980565b5050600c80546001600160a01b03199081166001600160a01b038c811691909117909255600d805482168b8416179055600e805482168a841617905560088054821689841617905560068054821688841617905560078054909116918616919091179055506040805180820182526224ea008152601460209182015270140000000000000000000000000024ea00600f5581516060810183526064815260c891810182905290910152601080546001600160c01b03191670c800000000000000c800000000000000641790556013805460ff19908116600190811790925560118054909116909117905562015180601555601d620006bc838262000980565b50601e620006cb828262000980565b50505050505050505062000a4c565b82602881019282156200070b579160200282015b828111156200070b578251825591602001919060010190620006ee565b50620007199291506200071d565b5090565b5b808211156200071957600081556001016200071e565b80516001600160a01b03811681146200074c57600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b600082601f8301126200077957600080fd5b81516001600160401b038082111562000796576200079662000751565b604051601f8301601f19908116603f01168101908282118183101715620007c157620007c162000751565b81604052838152602092508683858801011115620007de57600080fd5b600091505b83821015620008025785820183015181830184015290820190620007e3565b600093810190920192909252949350505050565b600080600080600080600080610100898b0312156200083457600080fd5b6200083f8962000734565b97506200084f60208a0162000734565b96506200085f60408a0162000734565b95506200086f60608a0162000734565b94506200087f60808a0162000734565b93506200088f60a08a0162000734565b60c08a01519093506001600160401b0380821115620008ad57600080fd5b620008bb8c838d0162000767565b935060e08b0151915080821115620008d257600080fd5b50620008e18b828c0162000767565b9150509295985092959890939650565b600181811c908216806200090657607f821691505b6020821081036200092757634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200097b57600081815260208120601f850160051c81016020861015620009565750805b601f850160051c820191505b81811015620009775782815560010162000962565b5050505b505050565b81516001600160401b038111156200099c576200099c62000751565b620009b481620009ad8454620008f1565b846200092d565b602080601f831160018114620009ec5760008415620009d35750858301515b600019600386901b1c1916600185901b17855562000977565b600085815260208120601f198616915b8281101562000a1d57888601518255948401946001909101908401620009fc565b508582101562000a3c5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b613c4d8062000a5c6000396000f3fe60806040526004361061038c5760003560e01c80635c975abb116101da578063a2510dae11610101578063d547cfb71161009a578063e8a3d4851161006c578063e8a3d48514610ba4578063e985e9c514610bb9578063eb3ab52414610bf4578063fbfee87614610c1457005b8063d547cfb714610b35578063df864c2314610b4a578063e2c6d41c14610b6a578063e838e56514610b8a57005b8063c34c08e5116100d3578063c34c08e514610ab3578063c87b56dd14610ad3578063d2a3250714610af3578063d340df1d14610b2057005b8063a2510dae14610a33578063a6d80a2714610a53578063b88d4fde14610a73578063bedb86fb14610a9357005b80638f228f93116101735780639ab24eb0116101455780639ab24eb0146109b35780639fd0506d146109d3578063a113607d146109f3578063a22cb46514610a1357005b80638f228f931461093c578063938e3d7b1461096957806394f38e8c1461098957806395d89b411461099e57005b806370a08231116101ac57806370a08231146108af57806376cb22e8146108cf578063857b767b146108ef5780638e4237981461090f57005b80635c975abb1461082a5780636352211e146108445780636d7ae837146108645780636f0ddd221461088f57005b806337a8a0dc116102be5780634d8e60461161025757806358f739e41161022957806358f739e4146107b05780635913f96d146107d05780635bb71b34146107f05780635c19a95c1461080a57005b80634d8e60461461070b5780635437988d14610750578063544d85641461077057806355f804b31461079057005b806342842e0e1161029057806342842e0e1461065f57806345bba9401461067f578063472b884d146106ac57806347e00ebc146106eb57005b806337a8a0dc146105e95780633be8ef3f146106095780633c7b1cd41461061f578063411b007e1461063f57005b806323b872dd116103305780632d88af4a116103025780632d88af4a146105755780632dc4a01714610595578063325b2d96146105b557806336331521146105c957005b806323b872dd146104bf578063285adddd146104df5780632b7ac3f31461053f5780632d3e8c931461055f57005b8063081812fc11610369578063081812fc1461040f578063095ea7b31461045d57806311acc1a71461047d5780631797c84c1461049257005b806301ffc9a71461039557806302e93ec1146103ca57806306fdde03146103ed57005b3661039357005b005b3480156103a157600080fd5b506103b56103b0366004613213565b610c2c565b60405190151581526020015b60405180910390f35b3480156103d657600080fd5b506103df601481565b6040519081526020016103c1565b3480156103f957600080fd5b50610402610c7e565b6040516103c19190613254565b34801561041b57600080fd5b5061044561042a366004613287565b6004602052600090815260409020546001600160a01b031681565b6040516001600160a01b0390911681526020016103c1565b34801561046957600080fd5b506103936104783660046132b5565b610d0c565b34801561048957600080fd5b506103df610df3565b34801561049e57600080fd5b506103df6104ad366004613287565b60186020526000908152604090205481565b3480156104cb57600080fd5b506103936104da3660046132e1565b610e17565b3480156104eb57600080fd5b50601054610515906001600160401b0380821691600160401b8104821691600160801b9091041683565b604080516001600160401b03948516815292841660208401529216918101919091526060016103c1565b34801561054b57600080fd5b50600a54610445906001600160a01b031681565b34801561056b57600080fd5b506103df60155481565b34801561058157600080fd5b50610393610590366004613322565b610e30565b3480156105a157600080fd5b506103936105b0366004613354565b610ef4565b3480156105c157600080fd5b5060016103b5565b3480156105d557600080fd5b506103936105e43660046133bc565b610f75565b3480156105f557600080fd5b50610393610604366004613420565b610f85565b34801561061557600080fd5b506103df61697881565b34801561062b57600080fd5b5061039361063a366004613450565b61101a565b34801561064b57600080fd5b50600654610445906001600160a01b031681565b34801561066b57600080fd5b5061039361067a3660046132e1565b6110c6565b34801561068b57600080fd5b506103df61069a366004613322565b601a6020526000908152604090205481565b3480156106b857600080fd5b50601f546106d390600160801b90046001600160801b031681565b6040516001600160801b0390911681526020016103c1565b3480156106f757600080fd5b50600b54610445906001600160a01b031681565b34801561071757600080fd5b50601f546001600160801b0380821691600160801b9004165b604080516001600160801b039384168152929091166020830152016103c1565b34801561075c57600080fd5b5061039361076b366004613322565b6111b9565b34801561077c57600080fd5b5061044561078b366004613322565b611266565b34801561079c57600080fd5b506103936107ab3660046134ba565b611298565b3480156107bc57600080fd5b506103936107cb366004613354565b611323565b3480156107dc57600080fd5b506103936107eb366004613354565b6113a9565b3480156107fc57600080fd5b506013546103b59060ff1681565b34801561081657600080fd5b50610393610825366004613322565b611434565b34801561083657600080fd5b506016546103b59060ff1681565b34801561085057600080fd5b5061044561085f366004613287565b6114b3565b34801561087057600080fd5b50600f54610730906001600160801b0380821691600160801b90041682565b34801561089b57600080fd5b506103df6108aa366004613287565b61150a565b3480156108bb57600080fd5b506103df6108ca366004613322565b611555565b3480156108db57600080fd5b506103936108ea366004613322565b6115b8565b3480156108fb57600080fd5b5061039361090a3660046134fb565b61164c565b34801561091b57600080fd5b506103df61092a366004613322565b60146020526000908152604090205481565b34801561094857600080fd5b506103df610957366004613322565b60126020526000908152604090205481565b34801561097557600080fd5b506103936109843660046134ba565b6116bb565b34801561099557600080fd5b5061039361172d565b3480156109aa57600080fd5b506104026117bc565b3480156109bf57600080fd5b506103df6109ce366004613322565b6117c9565b3480156109df57600080fd5b50600954610445906001600160a01b031681565b3480156109ff57600080fd5b506103df610a0e366004613287565b6117f7565b348015610a1f57600080fd5b50610393610a2e366004613546565b611877565b348015610a3f57600080fd5b50610393610a4e366004613450565b6118e3565b348015610a5f57600080fd5b50610393610a6e366004613322565b61195c565b348015610a7f57600080fd5b50610393610a8e36600461357f565b611a09565b348015610a9f57600080fd5b50610393610aae3660046135f1565b611af1565b348015610abf57600080fd5b50600854610445906001600160a01b031681565b348015610adf57600080fd5b50610402610aee366004613287565b611b8d565b348015610aff57600080fd5b506103df610b0e366004613322565b601b6020526000908152604090205481565b348015610b2c57600080fd5b50610393611c9f565b348015610b4157600080fd5b50610402611d3c565b348015610b5657600080fd5b506103df610b65366004613322565b611d49565b348015610b7657600080fd5b50600754610445906001600160a01b031681565b348015610b9657600080fd5b506011546103b59060ff1681565b348015610bb057600080fd5b50610402611f1a565b348015610bc557600080fd5b506103b5610bd436600461360e565b600560209081526000928352604080842090915290825290205460ff1681565b348015610c0057600080fd5b50601f546106d3906001600160801b031681565b348015610c2057600080fd5b506103df637735940081565b60006301ffc9a760e01b6001600160e01b031983161480610c5d57506380ac58cd60e01b6001600160e01b03198316145b80610c785750635b5e139f60e01b6001600160e01b03198316145b92915050565b60008054610c8b9061363c565b80601f0160208091040260200160405190810160405280929190818152602001828054610cb79061363c565b8015610d045780601f10610cd957610100808354040283529160200191610d04565b820191906000526020600020905b815481529060010190602001808311610ce757829003601f168201915b505050505081565b6000818152600260205260409020546001600160a01b031633811480610d5557506001600160a01b038116600090815260056020908152604080832033845290915290205460ff165b610d975760405162461bcd60e51b815260206004820152600e60248201526d1393d517d055551213d49256915160921b60448201526064015b60405180910390fd5b60008281526004602052604080822080546001600160a01b0319166001600160a01b0387811691821790925591518593918516917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591a4505050565b6000610e056001600160a01b03611d49565b601c54610e12919061368c565b905090565b604051630517a52360e41b815260040160405180910390fd5b6008546001600160a01b03163314801590610e5657506007546001600160a01b03163314155b8015610e6d57506006546001600160a01b03163314155b15610e8b5760405163ea8e4eb560e01b815260040160405180910390fd5b600954604080516001600160a01b03928316815291831660208301527fce932f997de7d15c38f57fe533bddcd74b6560acb995bdd231da68ed3af22dfe910160405180910390a1600980546001600160a01b0319166001600160a01b0392909216919091179055565b6008546001600160a01b03163314610f1f5760405163ea8e4eb560e01b815260040160405180910390fd5b6010805467ffffffffffffffff19166001600160401b0383169081179091556040519081527fbcf22ad7361f78458cd162cd291861a99c58be848cff080f08d1f6991f8aa49e906020015b60405180910390a150565b610f80838383611f27565b505050565b6008546001600160a01b03163314610fb05760405163ea8e4eb560e01b815260040160405180910390fd5b6011805484151560ff19918216811790925560138054851515921682179055601583905560408051928352602083019190915281018290527fbe343bfc5b51c0897197b9607c9e9a5116528d9a0156e4df5f146d39a020e5219060600160405180910390a1505050565b6008546001600160a01b031633146110455760405163ea8e4eb560e01b815260040160405180910390fd5b806001600160801b031660000361106f57604051630309cb8760e51b815260040160405180910390fd5b600f80546fffffffffffffffffffffffffffffffff19166001600160801b0383169081179091556040519081527fc73c2a2bcffa7fa8054797c5e4f48a83008619e351a32b7ac7f48a8ab2c84c7e90602001610f6a565b6110d1838383610e17565b6001600160a01b0382163b158061117a5750604051630a85bd0160e11b8082523360048301526001600160a01b03858116602484015260448301849052608060648401526000608484015290919084169063150b7a029060a4016020604051808303816000875af115801561114a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061116e919061369f565b6001600160e01b031916145b610f805760405162461bcd60e51b815260206004820152601060248201526f155394d0519157d49150d2541251539560821b6044820152606401610d8e565b6006546001600160a01b031633148015906111df57506007546001600160a01b03163314155b156111fd5760405163ea8e4eb560e01b815260040160405180910390fd5b600a54604080516001600160a01b03928316815291831660208301527f2ff4895c300d6993c27f2bb507b4b59d29464dc640af727383451365631ba8b2910160405180910390a1600a80546001600160a01b0319166001600160a01b0392909216919091179055565b6001600160a01b03808216600090815260196020526040812054909116801561128f5780611291565b825b9392505050565b6006546001600160a01b031633148015906112be57506007546001600160a01b03163314155b156112dc5760405163ea8e4eb560e01b815260040160405180910390fd5b7f5411e8ebf1636d9e83d5fc4900bf80cbac82e8790da2a4c94db4895e889eedf6601d61130a838583613718565b60405161131791906137d7565b60405180910390a15050565b6008546001600160a01b0316331461134e5760405163ea8e4eb560e01b815260040160405180910390fd5b6010805467ffffffffffffffff60801b1916600160801b6001600160401b038416908102919091179091556040519081527ff869d8acf2c70483110d4a26b89c5d2a66debd3c29df24c1000a3be12d2d86d990602001610f6a565b6008546001600160a01b031633146113d45760405163ea8e4eb560e01b815260040160405180910390fd5b601080546fffffffffffffffff00000000000000001916600160401b6001600160401b038416908102919091179091556040519081527f57586600c57c1d016eefd84f76fe9697155dc45acbce61da494952312882381890602001610f6a565b6001600160a01b0381166114455750335b60135460ff16801561147357506015543360009081526014602052604090205442916114709161368c565b11155b156114a65760005a905061148733836122cf565b3360009081526014602052604090204290556114a2816126b6565b5050565b6114b033826122cf565b50565b6000818152600260205260409020546001600160a01b0316806115055760405162461bcd60e51b815260206004820152600a6024820152691393d517d3525395115160b21b6044820152606401610d8e565b919050565b6000612710821061151d57506000919050565b61152b60ff80841690613862565b6020600884901c6028811061154257611542613875565b0154901c600116600a610c78919061388b565b60006001600160a01b03821661159c5760405162461bcd60e51b815260206004820152600c60248201526b5a45524f5f4144445245535360a01b6044820152606401610d8e565b506001600160a01b031660009081526003602052604090205490565b6006546001600160a01b031633146115e35760405163ea8e4eb560e01b815260040160405180910390fd5b600b54604080516001600160a01b03928316815291831660208301527fb81319a9bb8b17fae110bb40da7c54c734732f52530117d5700894fb45e388bf910160405180910390a1600b80546001600160a01b0319166001600160a01b0392909216919091179055565b60115460ff16801561167a57506015543360009081526012602052604090205442916116779161368c565b11155b156116b05760005a905061168f8484846127bd565b3360009081526012602052604090204290556116aa816126b6565b50505050565b610f808383836127bd565b6006546001600160a01b031633148015906116e157506007546001600160a01b03163314155b156116ff5760405163ea8e4eb560e01b815260040160405180910390fd5b7fd5ee5eaf65263bab5d569890714d123ad48a9e54409d35e71d374f3dd300bba0601e61130a838583613718565b6006546001600160a01b031633146117585760405163ea8e4eb560e01b815260040160405180910390fd5b600654604080516001600160a01b039092168252600060208301527fdb8dcc8712c6b41e8da769643922645a1221ad9c79beaf28920e2a5d5a893a62910160405180910390a1600680546001600160a01b0319908116909155600b80549091169055565b60018054610c8b9061363c565b60006117d482611d49565b6001600160a01b0383166000908152601b6020526040902054610c78919061368c565b600080611803836114b3565b6001600160a01b03160361182a57604051634a1850bf60e11b815260040160405180910390fd5b6000612710831061184657611841600260146138a2565b611849565b60145b90506118548361150a565b60008481526017602052604090205461186d908361368c565b611291919061368c565b3360008181526005602090815260408083206001600160a01b03871680855290835292819020805460ff191686151590811790915590519081529192917f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a35050565b6008546001600160a01b0316331461190e5760405163ea8e4eb560e01b815260040160405180910390fd5b600f80546001600160801b03908116600160801b918416918202179091556040519081527fe213d3449d5ab338ffd40007fe5a97d45d0418c1f0dc502f7925cda3fc78c8af90602001610f6a565b6006546001600160a01b0316331480159061198257506007546001600160a01b03163314155b156119a05760405163ea8e4eb560e01b815260040160405180910390fd5b600754604080516001600160a01b03928316815291831660208301527f66a019a63262ba85572d64812414a277be4e9069feaf5b182f95e4b6e529c3a4910160405180910390a1600780546001600160a01b0319166001600160a01b0392909216919091179055565b611a14858585610e17565b6001600160a01b0384163b1580611aab5750604051630a85bd0160e11b808252906001600160a01b0386169063150b7a0290611a5c9033908a908990899089906004016138c4565b6020604051808303816000875af1158015611a7b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a9f919061369f565b6001600160e01b031916145b611aea5760405162461bcd60e51b815260206004820152601060248201526f155394d0519157d49150d2541251539560821b6044820152606401610d8e565b5050505050565b6006546001600160a01b03163314801590611b1757506007546001600160a01b03163314155b8015611b2e57506009546001600160a01b03163314155b15611b4c5760405163ea8e4eb560e01b815260040160405180910390fd5b6016805460ff19168215159081179091556040519081527f608c68cec60453b4c976616f2c75d7dc520288e1fcf03656b57f7d7bddc8492090602001610f6a565b60606000611b9a836114b3565b6001600160a01b031603611bc157604051634a1850bf60e11b815260040160405180910390fd5b6000601d8054611bd09061363c565b80601f0160208091040260200160405190810160405280929190818152602001828054611bfc9061363c565b8015611c495780601f10611c1e57610100808354040283529160200191611c49565b820191906000526020600020905b815481529060010190602001808311611c2c57829003601f168201915b505050505090506000815111611c6e5760405180602001604052806000815250611291565b80611c788461297b565b604051602001611c89929190613918565b6040516020818303038152906040529392505050565b600b546001600160a01b03163314611cca5760405163ea8e4eb560e01b815260040160405180910390fd5b600654600b54604080516001600160a01b0393841681529290911660208301527fdb8dcc8712c6b41e8da769643922645a1221ad9c79beaf28920e2a5d5a893a62910160405180910390a1600b8054600680546001600160a01b03199081166001600160a01b03841617909155169055565b601d8054610c8b9061363c565b60008080806002600160a01b03196001600160a01b03861601611de957600e60009054906101000a90046001600160a01b03166001600160a01b031663afb417616040518163ffffffff1660e01b8152600401606060405180830381865afa158015611db9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ddd9190613957565b91945092509050611e89565b6001600160a01b0385166000908152601b60205260408120549003611e1357506000949350505050565b600e546040516331b7e5d760e11b81526001600160a01b0387811660048301529091169063636fcbae90602401606060405180830381865afa158015611e5d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e819190613957565b919450925090505b604080516060810182526010546001600160401b038082168352600160401b820481166020840152600160801b9091041691810182905290606490611ece9084613999565b6020830151611edd9086613999565b8351611ee99088613999565b611ef391906139c4565b611efd91906139c4565b6001600160401b0316611f1091906138a2565b9695505050505050565b601e8054610c8b9061363c565b600e5460408051635584c4f960e01b815290516000926001600160a01b031691635584c4f991600480830192869291908290030181865afa158015611f70573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611f989190810190613a1b565b905060005b815181101561214f57600e5482516001600160a01b039091169063e23a9a5290849084908110611fcf57611fcf613875565b6020026020010151611fe033611266565b6040516001600160e01b031960e085901b16815260048101929092526001600160a01b03166024820152604401606060405180830381865afa15801561202a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061204e9190613ac0565b511561206d57604051635a8181f760e01b815260040160405180910390fd5b600e5482516000916001600160a01b031690636e7685309085908590811061209757612097613875565b60200260200101516040518263ffffffff1660e01b81526004016120bd91815260200190565b606060405180830381865afa1580156120da573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120fe9190613b3f565b5091505061210b33611266565b6001600160a01b0316816001600160a01b03160361213c57604051635a8181f760e01b815260040160405180910390fd5b508061214781613b78565b915050611f9d565b5082600081900361217357604051630309cb8760e51b815260040160405180910390fd5b6000805b828110156121bf576121a187878381811061219457612194613875565b90506020020135866129bf565b6121ab908361368c565b9150806121b781613b78565b915050612177565b50336000908152601a6020526040812080548392906121df908490613862565b90915550819050601b60006121f333611266565b6001600160a01b03166001600160a01b0316815260200190815260200160002060008282546122229190613862565b9250508190555080601c600082825461223b9190613862565b9091555061224a905033611266565b6001600160a01b0316330361227f57336000908152601b6020526040812054900361227a5761227a336000612b90565b6122c7565b601b600061228c33611266565b6001600160a01b03166001600160a01b03168152602001908152602001600020546000036122c7576122c76122c033611266565b6000612b90565b505050505050565b600e5460408051635584c4f960e01b815290516000926001600160a01b031691635584c4f991600480830192869291908290030181865afa158015612318573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526123409190810190613a1b565b905060005b81518110156124f757600e5482516001600160a01b039091169063e23a9a529084908490811061237757612377613875565b602002602001015161238833611266565b6040516001600160e01b031960e085901b16815260048101929092526001600160a01b03166024820152604401606060405180830381865afa1580156123d2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123f69190613ac0565b511561241557604051635a8181f760e01b815260040160405180910390fd5b600e5482516000916001600160a01b031690636e7685309085908590811061243f5761243f613875565b60200260200101516040518263ffffffff1660e01b815260040161246591815260200190565b606060405180830381865afa158015612482573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124a69190613b3f565b509150506124b333611266565b6001600160a01b0316816001600160a01b0316036124e457604051635a8181f760e01b815260040160405180910390fd5b50806124ef81613b78565b915050612345565b50600061250384611266565b9050826001600160a01b0316816001600160a01b0316036125375760405163a9e649e960e01b815260040160405180910390fd5b836001600160a01b0316836001600160a01b0316146125565782612559565b60005b6001600160a01b03858116600090815260196020908152604080832080546001600160a01b0319169590941694909417909255601a90915290812054908190036125b65760405163a9e649e960e01b815260040160405180910390fd5b6001600160a01b0382166000908152601b6020526040812080548392906125de908490613862565b90915550506001600160a01b0384166000908152601b60205260408120805483929061260b90849061368c565b90915550506001600160a01b0382166000908152601b6020526040812054900361263a5761263a826000612b90565b6001600160a01b0384166000908152601b602052604090205481900361266557612665846001612b90565b836001600160a01b0316826001600160a01b0316866001600160a01b03167f3134e8a2e6d97e929a7e54011ea5485d7d196dd5f0ba4d4ef95803e8e3fc257f60405160405180910390a45050505050565b60006126c83a63773594004801612dd3565b905060006169785a840301905081810247811115612722576040805133815260208101839052478183015290517fe243285251dce839836e2f4e8bda33b6d0e646af39e99b141e3a211afb1910e59181900360600190a150475b604051600090339083908381818185875af1925050503d8060008114612764576040519150601f19603f3d011682016040523d82523d6000602084013e612769565b606091505b505060408051338152602081018590528215158183015247606082015290519192507fc279025f2293c0e6ca359933c1757bef4d673f2aced8f49ad6facea3a3e623a6919081900360800190a15050505050565b60165460ff16156127e1576040516313d0ff5960e31b815260040160405180910390fd5b6000811180156127f057504281105b1561280e57604051630309cb8760e51b815260040160405180910390fd5b600f546001600160801b0316811580159061283157508061282f4284613862565b115b1561284357612840814261368c565b91505b82600081900361286657604051630309cb8760e51b815260040160405180910390fd5b6000805b828110156128b25761289487878381811061288757612887613875565b9050602002013586612de2565b61289e908361368c565b9150806128aa81613b78565b91505061286a565b50336000908152601a6020526040812080548392906128d290849061368c565b90915550819050601b60006128e633611266565b6001600160a01b03166001600160a01b031681526020019081526020016000206000828254612915919061368c565b9250508190555080601c600082825461292e919061368c565b90915550819050601b600061294233611266565b6001600160a01b03166001600160a01b0316815260200190815260200160002054036122c7576122c761297433611266565b6001612b90565b606060a06040510180604052602081039150506000815280825b600183039250600a81066030018353600a9004806129955750819003601f19909101908152919050565b6000806129cb846114b3565b9050336001600160a01b038216146129f65760405163ea8e4eb560e01b815260040160405180910390fd5b600084815260186020526040902054421015612a2557604051635a8181f760e01b815260040160405180910390fd5b6000612710851015612a835750600c54601f80546001600160a01b0390921691600090612a5a906001600160801b0316613b91565b91906101000a8154816001600160801b0302191690836001600160801b03160217905550612ad8565b50600d54601f80546001600160a01b0390921691601090612ab390600160801b90046001600160801b0316613b91565b91906101000a8154816001600160801b0302191690836001600160801b031602179055505b604051632142170760e11b81523060048201526001600160a01b038581166024830152604482018790528216906342842e0e90606401600060405180830381600087803b158015612b2857600080fd5b505af1158015612b3c573d6000803e3d6000fd5b505050506000612b4b866117f7565b9050612b5686613025565b60008681526018602052604090205415612b8757600086815260186020908152604080832083905560179091528120555b95945050505050565b600e546040516331b7e5d760e11b81526001600160a01b038481166004830152600092839283929091169063636fcbae90602401606060405180830381865afa158015612be1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c059190613957565b9250925092506000806000600e60009054906101000a90046001600160a01b03166001600160a01b031663afb417616040518163ffffffff1660e01b8152600401606060405180830381865afa158015612c63573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c879190613957565b9250925092508615612d3057600e546001600160a01b0316635753f769612cae88866139c4565b612cb888866139c4565b612cc288866139c4565b60405160e085901b6001600160e01b03191681526001600160401b03938416600482015291831660248301529091166044820152606401600060405180830381600087803b158015612d1357600080fd5b505af1158015612d27573d6000803e3d6000fd5b50505050612dc9565b600e546001600160a01b0316635753f769612d4b8886613bb4565b612d558886613bb4565b612d5f8886613bb4565b60405160e085901b6001600160e01b03191681526001600160401b03938416600482015291831660248301529091166044820152606401600060405180830381600087803b158015612db057600080fd5b505af1158015612dc4573d6000803e3d6000fd5b505050505b5050505050505050565b600081831061128f5781611291565b60008115612e5e576000838152601860205260408120839055600f546001600160801b0380821691600160801b900416612e1c4286613862565b612e26919061388b565b612e3091906138a2565b90506127108410612e4b57612e466002826138a2565b612e4d565b805b600085815260176020526040902055505b6000612710841015612ebd5750600c54601f80546001600160a01b03909216916001600160801b0316906000612e9383613bd4565b91906101000a8154816001600160801b0302191690836001600160801b0316021790555050612f13565b50600d54601f80546001600160a01b0390921691600160801b90046001600160801b0316906010612eed83613bd4565b91906101000a8154816001600160801b0302191690836001600160801b03160217905550505b6040516331a9108f60e11b8152600481018590526000906001600160a01b03831690636352211e90602401602060405180830381865afa158015612f5b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f7f9190613bfa565b9050336001600160a01b03821614612faa5760405163ea8e4eb560e01b815260040160405180910390fd5b6040516323b872dd60e01b81526001600160a01b038281166004830152306024830152604482018790528316906323b872dd90606401600060405180830381600087803b158015612ffa57600080fd5b505af115801561300e573d6000803e3d6000fd5b5050505061301c33866130f2565b612b87856117f7565b6000818152600260205260409020546001600160a01b0316806130775760405162461bcd60e51b815260206004820152600a6024820152691393d517d3525395115160b21b6044820152606401610d8e565b6001600160a01b038116600081815260036020908152604080832080546000190190558583526002825280832080546001600160a01b031990811690915560049092528083208054909216909155518492907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908390a45050565b6001600160a01b03821661313c5760405162461bcd60e51b81526020600482015260116024820152701253959053125117d49150d25412515395607a1b6044820152606401610d8e565b6000818152600260205260409020546001600160a01b0316156131925760405162461bcd60e51b815260206004820152600e60248201526d1053149150511657d3525395115160921b6044820152606401610d8e565b6001600160a01b038216600081815260036020908152604080832080546001019055848352600290915280822080546001600160a01b0319168417905551839291907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a45050565b6001600160e01b0319811681146114b057600080fd5b60006020828403121561322557600080fd5b8135611291816131fd565b60005b8381101561324b578181015183820152602001613233565b50506000910152565b6020815260008251806020840152613273816040850160208701613230565b601f01601f19169190910160400192915050565b60006020828403121561329957600080fd5b5035919050565b6001600160a01b03811681146114b057600080fd5b600080604083850312156132c857600080fd5b82356132d3816132a0565b946020939093013593505050565b6000806000606084860312156132f657600080fd5b8335613301816132a0565b92506020840135613311816132a0565b929592945050506040919091013590565b60006020828403121561333457600080fd5b8135611291816132a0565b6001600160401b03811681146114b057600080fd5b60006020828403121561336657600080fd5b81356112918161333f565b60008083601f84011261338357600080fd5b5081356001600160401b0381111561339a57600080fd5b6020830191508360208260051b85010111156133b557600080fd5b9250929050565b6000806000604084860312156133d157600080fd5b83356001600160401b038111156133e757600080fd5b6133f386828701613371565b9094509250506020840135613407816132a0565b809150509250925092565b80151581146114b057600080fd5b60008060006060848603121561343557600080fd5b833561344081613412565b9250602084013561331181613412565b60006020828403121561346257600080fd5b81356001600160801b038116811461129157600080fd5b60008083601f84011261348b57600080fd5b5081356001600160401b038111156134a257600080fd5b6020830191508360208285010111156133b557600080fd5b600080602083850312156134cd57600080fd5b82356001600160401b038111156134e357600080fd5b6134ef85828601613479565b90969095509350505050565b60008060006040848603121561351057600080fd5b83356001600160401b0381111561352657600080fd5b61353286828701613371565b909790965060209590950135949350505050565b6000806040838503121561355957600080fd5b8235613564816132a0565b9150602083013561357481613412565b809150509250929050565b60008060008060006080868803121561359757600080fd5b85356135a2816132a0565b945060208601356135b2816132a0565b93506040860135925060608601356001600160401b038111156135d457600080fd5b6135e088828901613479565b969995985093965092949392505050565b60006020828403121561360357600080fd5b813561129181613412565b6000806040838503121561362157600080fd5b823561362c816132a0565b91506020830135613574816132a0565b600181811c9082168061365057607f821691505b60208210810361367057634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052601160045260246000fd5b80820180821115610c7857610c78613676565b6000602082840312156136b157600080fd5b8151611291816131fd565b634e487b7160e01b600052604160045260246000fd5b601f821115610f8057600081815260208120601f850160051c810160208610156136f95750805b601f850160051c820191505b818110156122c757828155600101613705565b6001600160401b0383111561372f5761372f6136bc565b6137438361373d835461363c565b836136d2565b6000601f841160018114613777576000851561375f5750838201355b600019600387901b1c1916600186901b178355611aea565b600083815260209020601f19861690835b828110156137a85786850135825560209485019460019092019101613788565b50868210156137c55760001960f88860031b161c19848701351681555b505060018560011b0183555050505050565b60006020808352600084546137eb8161363c565b8084870152604060018084166000811461380c576001811461382657613854565b60ff1985168984015283151560051b890183019550613854565b896000528660002060005b8581101561384c5781548b8201860152908301908801613831565b8a0184019650505b509398975050505050505050565b81810381811115610c7857610c78613676565b634e487b7160e01b600052603260045260246000fd5b8082028115828204841417610c7857610c78613676565b6000826138bf57634e487b7160e01b600052601260045260246000fd5b500490565b6001600160a01b038681168252851660208201526040810184905260806060820181905281018290526000828460a0840137600060a0848401015260a0601f19601f85011683010190509695505050505050565b6000835161392a818460208801613230565b83519083019061393e818360208801613230565b64173539b7b760d91b9101908152600501949350505050565b60008060006060848603121561396c57600080fd5b83516139778161333f565b60208501519093506139888161333f565b60408501519092506134078161333f565b6001600160401b038181168382160280821691908281146139bc576139bc613676565b505092915050565b6001600160401b038181168382160190808211156139e4576139e4613676565b5092915050565b604051601f8201601f191681016001600160401b0381118282101715613a1357613a136136bc565b604052919050565b60006020808385031215613a2e57600080fd5b82516001600160401b0380821115613a4557600080fd5b818501915085601f830112613a5957600080fd5b815181811115613a6b57613a6b6136bc565b8060051b9150613a7c8483016139eb565b8181529183018401918481019088841115613a9657600080fd5b938501935b83851015613ab457845182529385019390850190613a9b565b98975050505050505050565b600060608284031215613ad257600080fd5b604051606081018181106001600160401b0382111715613af457613af46136bc565b6040528251613b0281613412565b8152602083015160ff81168114613b1857600080fd5b6020820152604083015162ffffff81168114613b3357600080fd5b60408201529392505050565b600080600060608486031215613b5457600080fd5b835192506020840151613b66816132a0565b80925050604084015190509250925092565b600060018201613b8a57613b8a613676565b5060010190565b60006001600160801b03821680613baa57613baa613676565b6000190192915050565b6001600160401b038281168282160390808211156139e4576139e4613676565b60006001600160801b03808316818103613bf057613bf0613676565b6001019392505050565b600060208284031215613c0c57600080fd5b8151611291816132a056fea2646970667358221220d89063dda8c1849b792890900b569e220384c433db58c6e6223685c6dfeec3a064736f6c634300081100330000000000000000000000001fec856e25f757fed06eb90548b0224e910957380000000000000000000000002cfbcb9e9c3d1ab06ef332f535266444aa8d9570000000000000000000000000053d938a4d2a6df86d837d66a037444d7bacf3b90000000000000000000000003c43e86c4c3ba4d2b6c15439d2d97556985814a2000000000000000000000000b7ccb0ee5c06562282048f95e27c73b148dcb6d20000000000000000000000002630ef1e79e38ec1e42db2a891ce1b62542a236200000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000002168747470733a2f2f70756e6b732e33646672616e6b656e70756e6b732e636f6d2f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005168747470733a2f2f676174657761792e70696e6174612e636c6f75642f697066732f516d53464e765a466d5367766b65425a6150646f48586e55346e364243694b783734776257636a376245466153742f000000000000000000000000000000

Deployed Bytecode

0x60806040526004361061038c5760003560e01c80635c975abb116101da578063a2510dae11610101578063d547cfb71161009a578063e8a3d4851161006c578063e8a3d48514610ba4578063e985e9c514610bb9578063eb3ab52414610bf4578063fbfee87614610c1457005b8063d547cfb714610b35578063df864c2314610b4a578063e2c6d41c14610b6a578063e838e56514610b8a57005b8063c34c08e5116100d3578063c34c08e514610ab3578063c87b56dd14610ad3578063d2a3250714610af3578063d340df1d14610b2057005b8063a2510dae14610a33578063a6d80a2714610a53578063b88d4fde14610a73578063bedb86fb14610a9357005b80638f228f93116101735780639ab24eb0116101455780639ab24eb0146109b35780639fd0506d146109d3578063a113607d146109f3578063a22cb46514610a1357005b80638f228f931461093c578063938e3d7b1461096957806394f38e8c1461098957806395d89b411461099e57005b806370a08231116101ac57806370a08231146108af57806376cb22e8146108cf578063857b767b146108ef5780638e4237981461090f57005b80635c975abb1461082a5780636352211e146108445780636d7ae837146108645780636f0ddd221461088f57005b806337a8a0dc116102be5780634d8e60461161025757806358f739e41161022957806358f739e4146107b05780635913f96d146107d05780635bb71b34146107f05780635c19a95c1461080a57005b80634d8e60461461070b5780635437988d14610750578063544d85641461077057806355f804b31461079057005b806342842e0e1161029057806342842e0e1461065f57806345bba9401461067f578063472b884d146106ac57806347e00ebc146106eb57005b806337a8a0dc146105e95780633be8ef3f146106095780633c7b1cd41461061f578063411b007e1461063f57005b806323b872dd116103305780632d88af4a116103025780632d88af4a146105755780632dc4a01714610595578063325b2d96146105b557806336331521146105c957005b806323b872dd146104bf578063285adddd146104df5780632b7ac3f31461053f5780632d3e8c931461055f57005b8063081812fc11610369578063081812fc1461040f578063095ea7b31461045d57806311acc1a71461047d5780631797c84c1461049257005b806301ffc9a71461039557806302e93ec1146103ca57806306fdde03146103ed57005b3661039357005b005b3480156103a157600080fd5b506103b56103b0366004613213565b610c2c565b60405190151581526020015b60405180910390f35b3480156103d657600080fd5b506103df601481565b6040519081526020016103c1565b3480156103f957600080fd5b50610402610c7e565b6040516103c19190613254565b34801561041b57600080fd5b5061044561042a366004613287565b6004602052600090815260409020546001600160a01b031681565b6040516001600160a01b0390911681526020016103c1565b34801561046957600080fd5b506103936104783660046132b5565b610d0c565b34801561048957600080fd5b506103df610df3565b34801561049e57600080fd5b506103df6104ad366004613287565b60186020526000908152604090205481565b3480156104cb57600080fd5b506103936104da3660046132e1565b610e17565b3480156104eb57600080fd5b50601054610515906001600160401b0380821691600160401b8104821691600160801b9091041683565b604080516001600160401b03948516815292841660208401529216918101919091526060016103c1565b34801561054b57600080fd5b50600a54610445906001600160a01b031681565b34801561056b57600080fd5b506103df60155481565b34801561058157600080fd5b50610393610590366004613322565b610e30565b3480156105a157600080fd5b506103936105b0366004613354565b610ef4565b3480156105c157600080fd5b5060016103b5565b3480156105d557600080fd5b506103936105e43660046133bc565b610f75565b3480156105f557600080fd5b50610393610604366004613420565b610f85565b34801561061557600080fd5b506103df61697881565b34801561062b57600080fd5b5061039361063a366004613450565b61101a565b34801561064b57600080fd5b50600654610445906001600160a01b031681565b34801561066b57600080fd5b5061039361067a3660046132e1565b6110c6565b34801561068b57600080fd5b506103df61069a366004613322565b601a6020526000908152604090205481565b3480156106b857600080fd5b50601f546106d390600160801b90046001600160801b031681565b6040516001600160801b0390911681526020016103c1565b3480156106f757600080fd5b50600b54610445906001600160a01b031681565b34801561071757600080fd5b50601f546001600160801b0380821691600160801b9004165b604080516001600160801b039384168152929091166020830152016103c1565b34801561075c57600080fd5b5061039361076b366004613322565b6111b9565b34801561077c57600080fd5b5061044561078b366004613322565b611266565b34801561079c57600080fd5b506103936107ab3660046134ba565b611298565b3480156107bc57600080fd5b506103936107cb366004613354565b611323565b3480156107dc57600080fd5b506103936107eb366004613354565b6113a9565b3480156107fc57600080fd5b506013546103b59060ff1681565b34801561081657600080fd5b50610393610825366004613322565b611434565b34801561083657600080fd5b506016546103b59060ff1681565b34801561085057600080fd5b5061044561085f366004613287565b6114b3565b34801561087057600080fd5b50600f54610730906001600160801b0380821691600160801b90041682565b34801561089b57600080fd5b506103df6108aa366004613287565b61150a565b3480156108bb57600080fd5b506103df6108ca366004613322565b611555565b3480156108db57600080fd5b506103936108ea366004613322565b6115b8565b3480156108fb57600080fd5b5061039361090a3660046134fb565b61164c565b34801561091b57600080fd5b506103df61092a366004613322565b60146020526000908152604090205481565b34801561094857600080fd5b506103df610957366004613322565b60126020526000908152604090205481565b34801561097557600080fd5b506103936109843660046134ba565b6116bb565b34801561099557600080fd5b5061039361172d565b3480156109aa57600080fd5b506104026117bc565b3480156109bf57600080fd5b506103df6109ce366004613322565b6117c9565b3480156109df57600080fd5b50600954610445906001600160a01b031681565b3480156109ff57600080fd5b506103df610a0e366004613287565b6117f7565b348015610a1f57600080fd5b50610393610a2e366004613546565b611877565b348015610a3f57600080fd5b50610393610a4e366004613450565b6118e3565b348015610a5f57600080fd5b50610393610a6e366004613322565b61195c565b348015610a7f57600080fd5b50610393610a8e36600461357f565b611a09565b348015610a9f57600080fd5b50610393610aae3660046135f1565b611af1565b348015610abf57600080fd5b50600854610445906001600160a01b031681565b348015610adf57600080fd5b50610402610aee366004613287565b611b8d565b348015610aff57600080fd5b506103df610b0e366004613322565b601b6020526000908152604090205481565b348015610b2c57600080fd5b50610393611c9f565b348015610b4157600080fd5b50610402611d3c565b348015610b5657600080fd5b506103df610b65366004613322565b611d49565b348015610b7657600080fd5b50600754610445906001600160a01b031681565b348015610b9657600080fd5b506011546103b59060ff1681565b348015610bb057600080fd5b50610402611f1a565b348015610bc557600080fd5b506103b5610bd436600461360e565b600560209081526000928352604080842090915290825290205460ff1681565b348015610c0057600080fd5b50601f546106d3906001600160801b031681565b348015610c2057600080fd5b506103df637735940081565b60006301ffc9a760e01b6001600160e01b031983161480610c5d57506380ac58cd60e01b6001600160e01b03198316145b80610c785750635b5e139f60e01b6001600160e01b03198316145b92915050565b60008054610c8b9061363c565b80601f0160208091040260200160405190810160405280929190818152602001828054610cb79061363c565b8015610d045780601f10610cd957610100808354040283529160200191610d04565b820191906000526020600020905b815481529060010190602001808311610ce757829003601f168201915b505050505081565b6000818152600260205260409020546001600160a01b031633811480610d5557506001600160a01b038116600090815260056020908152604080832033845290915290205460ff165b610d975760405162461bcd60e51b815260206004820152600e60248201526d1393d517d055551213d49256915160921b60448201526064015b60405180910390fd5b60008281526004602052604080822080546001600160a01b0319166001600160a01b0387811691821790925591518593918516917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591a4505050565b6000610e056001600160a01b03611d49565b601c54610e12919061368c565b905090565b604051630517a52360e41b815260040160405180910390fd5b6008546001600160a01b03163314801590610e5657506007546001600160a01b03163314155b8015610e6d57506006546001600160a01b03163314155b15610e8b5760405163ea8e4eb560e01b815260040160405180910390fd5b600954604080516001600160a01b03928316815291831660208301527fce932f997de7d15c38f57fe533bddcd74b6560acb995bdd231da68ed3af22dfe910160405180910390a1600980546001600160a01b0319166001600160a01b0392909216919091179055565b6008546001600160a01b03163314610f1f5760405163ea8e4eb560e01b815260040160405180910390fd5b6010805467ffffffffffffffff19166001600160401b0383169081179091556040519081527fbcf22ad7361f78458cd162cd291861a99c58be848cff080f08d1f6991f8aa49e906020015b60405180910390a150565b610f80838383611f27565b505050565b6008546001600160a01b03163314610fb05760405163ea8e4eb560e01b815260040160405180910390fd5b6011805484151560ff19918216811790925560138054851515921682179055601583905560408051928352602083019190915281018290527fbe343bfc5b51c0897197b9607c9e9a5116528d9a0156e4df5f146d39a020e5219060600160405180910390a1505050565b6008546001600160a01b031633146110455760405163ea8e4eb560e01b815260040160405180910390fd5b806001600160801b031660000361106f57604051630309cb8760e51b815260040160405180910390fd5b600f80546fffffffffffffffffffffffffffffffff19166001600160801b0383169081179091556040519081527fc73c2a2bcffa7fa8054797c5e4f48a83008619e351a32b7ac7f48a8ab2c84c7e90602001610f6a565b6110d1838383610e17565b6001600160a01b0382163b158061117a5750604051630a85bd0160e11b8082523360048301526001600160a01b03858116602484015260448301849052608060648401526000608484015290919084169063150b7a029060a4016020604051808303816000875af115801561114a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061116e919061369f565b6001600160e01b031916145b610f805760405162461bcd60e51b815260206004820152601060248201526f155394d0519157d49150d2541251539560821b6044820152606401610d8e565b6006546001600160a01b031633148015906111df57506007546001600160a01b03163314155b156111fd5760405163ea8e4eb560e01b815260040160405180910390fd5b600a54604080516001600160a01b03928316815291831660208301527f2ff4895c300d6993c27f2bb507b4b59d29464dc640af727383451365631ba8b2910160405180910390a1600a80546001600160a01b0319166001600160a01b0392909216919091179055565b6001600160a01b03808216600090815260196020526040812054909116801561128f5780611291565b825b9392505050565b6006546001600160a01b031633148015906112be57506007546001600160a01b03163314155b156112dc5760405163ea8e4eb560e01b815260040160405180910390fd5b7f5411e8ebf1636d9e83d5fc4900bf80cbac82e8790da2a4c94db4895e889eedf6601d61130a838583613718565b60405161131791906137d7565b60405180910390a15050565b6008546001600160a01b0316331461134e5760405163ea8e4eb560e01b815260040160405180910390fd5b6010805467ffffffffffffffff60801b1916600160801b6001600160401b038416908102919091179091556040519081527ff869d8acf2c70483110d4a26b89c5d2a66debd3c29df24c1000a3be12d2d86d990602001610f6a565b6008546001600160a01b031633146113d45760405163ea8e4eb560e01b815260040160405180910390fd5b601080546fffffffffffffffff00000000000000001916600160401b6001600160401b038416908102919091179091556040519081527f57586600c57c1d016eefd84f76fe9697155dc45acbce61da494952312882381890602001610f6a565b6001600160a01b0381166114455750335b60135460ff16801561147357506015543360009081526014602052604090205442916114709161368c565b11155b156114a65760005a905061148733836122cf565b3360009081526014602052604090204290556114a2816126b6565b5050565b6114b033826122cf565b50565b6000818152600260205260409020546001600160a01b0316806115055760405162461bcd60e51b815260206004820152600a6024820152691393d517d3525395115160b21b6044820152606401610d8e565b919050565b6000612710821061151d57506000919050565b61152b60ff80841690613862565b6020600884901c6028811061154257611542613875565b0154901c600116600a610c78919061388b565b60006001600160a01b03821661159c5760405162461bcd60e51b815260206004820152600c60248201526b5a45524f5f4144445245535360a01b6044820152606401610d8e565b506001600160a01b031660009081526003602052604090205490565b6006546001600160a01b031633146115e35760405163ea8e4eb560e01b815260040160405180910390fd5b600b54604080516001600160a01b03928316815291831660208301527fb81319a9bb8b17fae110bb40da7c54c734732f52530117d5700894fb45e388bf910160405180910390a1600b80546001600160a01b0319166001600160a01b0392909216919091179055565b60115460ff16801561167a57506015543360009081526012602052604090205442916116779161368c565b11155b156116b05760005a905061168f8484846127bd565b3360009081526012602052604090204290556116aa816126b6565b50505050565b610f808383836127bd565b6006546001600160a01b031633148015906116e157506007546001600160a01b03163314155b156116ff5760405163ea8e4eb560e01b815260040160405180910390fd5b7fd5ee5eaf65263bab5d569890714d123ad48a9e54409d35e71d374f3dd300bba0601e61130a838583613718565b6006546001600160a01b031633146117585760405163ea8e4eb560e01b815260040160405180910390fd5b600654604080516001600160a01b039092168252600060208301527fdb8dcc8712c6b41e8da769643922645a1221ad9c79beaf28920e2a5d5a893a62910160405180910390a1600680546001600160a01b0319908116909155600b80549091169055565b60018054610c8b9061363c565b60006117d482611d49565b6001600160a01b0383166000908152601b6020526040902054610c78919061368c565b600080611803836114b3565b6001600160a01b03160361182a57604051634a1850bf60e11b815260040160405180910390fd5b6000612710831061184657611841600260146138a2565b611849565b60145b90506118548361150a565b60008481526017602052604090205461186d908361368c565b611291919061368c565b3360008181526005602090815260408083206001600160a01b03871680855290835292819020805460ff191686151590811790915590519081529192917f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a35050565b6008546001600160a01b0316331461190e5760405163ea8e4eb560e01b815260040160405180910390fd5b600f80546001600160801b03908116600160801b918416918202179091556040519081527fe213d3449d5ab338ffd40007fe5a97d45d0418c1f0dc502f7925cda3fc78c8af90602001610f6a565b6006546001600160a01b0316331480159061198257506007546001600160a01b03163314155b156119a05760405163ea8e4eb560e01b815260040160405180910390fd5b600754604080516001600160a01b03928316815291831660208301527f66a019a63262ba85572d64812414a277be4e9069feaf5b182f95e4b6e529c3a4910160405180910390a1600780546001600160a01b0319166001600160a01b0392909216919091179055565b611a14858585610e17565b6001600160a01b0384163b1580611aab5750604051630a85bd0160e11b808252906001600160a01b0386169063150b7a0290611a5c9033908a908990899089906004016138c4565b6020604051808303816000875af1158015611a7b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a9f919061369f565b6001600160e01b031916145b611aea5760405162461bcd60e51b815260206004820152601060248201526f155394d0519157d49150d2541251539560821b6044820152606401610d8e565b5050505050565b6006546001600160a01b03163314801590611b1757506007546001600160a01b03163314155b8015611b2e57506009546001600160a01b03163314155b15611b4c5760405163ea8e4eb560e01b815260040160405180910390fd5b6016805460ff19168215159081179091556040519081527f608c68cec60453b4c976616f2c75d7dc520288e1fcf03656b57f7d7bddc8492090602001610f6a565b60606000611b9a836114b3565b6001600160a01b031603611bc157604051634a1850bf60e11b815260040160405180910390fd5b6000601d8054611bd09061363c565b80601f0160208091040260200160405190810160405280929190818152602001828054611bfc9061363c565b8015611c495780601f10611c1e57610100808354040283529160200191611c49565b820191906000526020600020905b815481529060010190602001808311611c2c57829003601f168201915b505050505090506000815111611c6e5760405180602001604052806000815250611291565b80611c788461297b565b604051602001611c89929190613918565b6040516020818303038152906040529392505050565b600b546001600160a01b03163314611cca5760405163ea8e4eb560e01b815260040160405180910390fd5b600654600b54604080516001600160a01b0393841681529290911660208301527fdb8dcc8712c6b41e8da769643922645a1221ad9c79beaf28920e2a5d5a893a62910160405180910390a1600b8054600680546001600160a01b03199081166001600160a01b03841617909155169055565b601d8054610c8b9061363c565b60008080806002600160a01b03196001600160a01b03861601611de957600e60009054906101000a90046001600160a01b03166001600160a01b031663afb417616040518163ffffffff1660e01b8152600401606060405180830381865afa158015611db9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ddd9190613957565b91945092509050611e89565b6001600160a01b0385166000908152601b60205260408120549003611e1357506000949350505050565b600e546040516331b7e5d760e11b81526001600160a01b0387811660048301529091169063636fcbae90602401606060405180830381865afa158015611e5d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e819190613957565b919450925090505b604080516060810182526010546001600160401b038082168352600160401b820481166020840152600160801b9091041691810182905290606490611ece9084613999565b6020830151611edd9086613999565b8351611ee99088613999565b611ef391906139c4565b611efd91906139c4565b6001600160401b0316611f1091906138a2565b9695505050505050565b601e8054610c8b9061363c565b600e5460408051635584c4f960e01b815290516000926001600160a01b031691635584c4f991600480830192869291908290030181865afa158015611f70573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611f989190810190613a1b565b905060005b815181101561214f57600e5482516001600160a01b039091169063e23a9a5290849084908110611fcf57611fcf613875565b6020026020010151611fe033611266565b6040516001600160e01b031960e085901b16815260048101929092526001600160a01b03166024820152604401606060405180830381865afa15801561202a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061204e9190613ac0565b511561206d57604051635a8181f760e01b815260040160405180910390fd5b600e5482516000916001600160a01b031690636e7685309085908590811061209757612097613875565b60200260200101516040518263ffffffff1660e01b81526004016120bd91815260200190565b606060405180830381865afa1580156120da573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120fe9190613b3f565b5091505061210b33611266565b6001600160a01b0316816001600160a01b03160361213c57604051635a8181f760e01b815260040160405180910390fd5b508061214781613b78565b915050611f9d565b5082600081900361217357604051630309cb8760e51b815260040160405180910390fd5b6000805b828110156121bf576121a187878381811061219457612194613875565b90506020020135866129bf565b6121ab908361368c565b9150806121b781613b78565b915050612177565b50336000908152601a6020526040812080548392906121df908490613862565b90915550819050601b60006121f333611266565b6001600160a01b03166001600160a01b0316815260200190815260200160002060008282546122229190613862565b9250508190555080601c600082825461223b9190613862565b9091555061224a905033611266565b6001600160a01b0316330361227f57336000908152601b6020526040812054900361227a5761227a336000612b90565b6122c7565b601b600061228c33611266565b6001600160a01b03166001600160a01b03168152602001908152602001600020546000036122c7576122c76122c033611266565b6000612b90565b505050505050565b600e5460408051635584c4f960e01b815290516000926001600160a01b031691635584c4f991600480830192869291908290030181865afa158015612318573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526123409190810190613a1b565b905060005b81518110156124f757600e5482516001600160a01b039091169063e23a9a529084908490811061237757612377613875565b602002602001015161238833611266565b6040516001600160e01b031960e085901b16815260048101929092526001600160a01b03166024820152604401606060405180830381865afa1580156123d2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123f69190613ac0565b511561241557604051635a8181f760e01b815260040160405180910390fd5b600e5482516000916001600160a01b031690636e7685309085908590811061243f5761243f613875565b60200260200101516040518263ffffffff1660e01b815260040161246591815260200190565b606060405180830381865afa158015612482573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124a69190613b3f565b509150506124b333611266565b6001600160a01b0316816001600160a01b0316036124e457604051635a8181f760e01b815260040160405180910390fd5b50806124ef81613b78565b915050612345565b50600061250384611266565b9050826001600160a01b0316816001600160a01b0316036125375760405163a9e649e960e01b815260040160405180910390fd5b836001600160a01b0316836001600160a01b0316146125565782612559565b60005b6001600160a01b03858116600090815260196020908152604080832080546001600160a01b0319169590941694909417909255601a90915290812054908190036125b65760405163a9e649e960e01b815260040160405180910390fd5b6001600160a01b0382166000908152601b6020526040812080548392906125de908490613862565b90915550506001600160a01b0384166000908152601b60205260408120805483929061260b90849061368c565b90915550506001600160a01b0382166000908152601b6020526040812054900361263a5761263a826000612b90565b6001600160a01b0384166000908152601b602052604090205481900361266557612665846001612b90565b836001600160a01b0316826001600160a01b0316866001600160a01b03167f3134e8a2e6d97e929a7e54011ea5485d7d196dd5f0ba4d4ef95803e8e3fc257f60405160405180910390a45050505050565b60006126c83a63773594004801612dd3565b905060006169785a840301905081810247811115612722576040805133815260208101839052478183015290517fe243285251dce839836e2f4e8bda33b6d0e646af39e99b141e3a211afb1910e59181900360600190a150475b604051600090339083908381818185875af1925050503d8060008114612764576040519150601f19603f3d011682016040523d82523d6000602084013e612769565b606091505b505060408051338152602081018590528215158183015247606082015290519192507fc279025f2293c0e6ca359933c1757bef4d673f2aced8f49ad6facea3a3e623a6919081900360800190a15050505050565b60165460ff16156127e1576040516313d0ff5960e31b815260040160405180910390fd5b6000811180156127f057504281105b1561280e57604051630309cb8760e51b815260040160405180910390fd5b600f546001600160801b0316811580159061283157508061282f4284613862565b115b1561284357612840814261368c565b91505b82600081900361286657604051630309cb8760e51b815260040160405180910390fd5b6000805b828110156128b25761289487878381811061288757612887613875565b9050602002013586612de2565b61289e908361368c565b9150806128aa81613b78565b91505061286a565b50336000908152601a6020526040812080548392906128d290849061368c565b90915550819050601b60006128e633611266565b6001600160a01b03166001600160a01b031681526020019081526020016000206000828254612915919061368c565b9250508190555080601c600082825461292e919061368c565b90915550819050601b600061294233611266565b6001600160a01b03166001600160a01b0316815260200190815260200160002054036122c7576122c761297433611266565b6001612b90565b606060a06040510180604052602081039150506000815280825b600183039250600a81066030018353600a9004806129955750819003601f19909101908152919050565b6000806129cb846114b3565b9050336001600160a01b038216146129f65760405163ea8e4eb560e01b815260040160405180910390fd5b600084815260186020526040902054421015612a2557604051635a8181f760e01b815260040160405180910390fd5b6000612710851015612a835750600c54601f80546001600160a01b0390921691600090612a5a906001600160801b0316613b91565b91906101000a8154816001600160801b0302191690836001600160801b03160217905550612ad8565b50600d54601f80546001600160a01b0390921691601090612ab390600160801b90046001600160801b0316613b91565b91906101000a8154816001600160801b0302191690836001600160801b031602179055505b604051632142170760e11b81523060048201526001600160a01b038581166024830152604482018790528216906342842e0e90606401600060405180830381600087803b158015612b2857600080fd5b505af1158015612b3c573d6000803e3d6000fd5b505050506000612b4b866117f7565b9050612b5686613025565b60008681526018602052604090205415612b8757600086815260186020908152604080832083905560179091528120555b95945050505050565b600e546040516331b7e5d760e11b81526001600160a01b038481166004830152600092839283929091169063636fcbae90602401606060405180830381865afa158015612be1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c059190613957565b9250925092506000806000600e60009054906101000a90046001600160a01b03166001600160a01b031663afb417616040518163ffffffff1660e01b8152600401606060405180830381865afa158015612c63573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c879190613957565b9250925092508615612d3057600e546001600160a01b0316635753f769612cae88866139c4565b612cb888866139c4565b612cc288866139c4565b60405160e085901b6001600160e01b03191681526001600160401b03938416600482015291831660248301529091166044820152606401600060405180830381600087803b158015612d1357600080fd5b505af1158015612d27573d6000803e3d6000fd5b50505050612dc9565b600e546001600160a01b0316635753f769612d4b8886613bb4565b612d558886613bb4565b612d5f8886613bb4565b60405160e085901b6001600160e01b03191681526001600160401b03938416600482015291831660248301529091166044820152606401600060405180830381600087803b158015612db057600080fd5b505af1158015612dc4573d6000803e3d6000fd5b505050505b5050505050505050565b600081831061128f5781611291565b60008115612e5e576000838152601860205260408120839055600f546001600160801b0380821691600160801b900416612e1c4286613862565b612e26919061388b565b612e3091906138a2565b90506127108410612e4b57612e466002826138a2565b612e4d565b805b600085815260176020526040902055505b6000612710841015612ebd5750600c54601f80546001600160a01b03909216916001600160801b0316906000612e9383613bd4565b91906101000a8154816001600160801b0302191690836001600160801b0316021790555050612f13565b50600d54601f80546001600160a01b0390921691600160801b90046001600160801b0316906010612eed83613bd4565b91906101000a8154816001600160801b0302191690836001600160801b03160217905550505b6040516331a9108f60e11b8152600481018590526000906001600160a01b03831690636352211e90602401602060405180830381865afa158015612f5b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f7f9190613bfa565b9050336001600160a01b03821614612faa5760405163ea8e4eb560e01b815260040160405180910390fd5b6040516323b872dd60e01b81526001600160a01b038281166004830152306024830152604482018790528316906323b872dd90606401600060405180830381600087803b158015612ffa57600080fd5b505af115801561300e573d6000803e3d6000fd5b5050505061301c33866130f2565b612b87856117f7565b6000818152600260205260409020546001600160a01b0316806130775760405162461bcd60e51b815260206004820152600a6024820152691393d517d3525395115160b21b6044820152606401610d8e565b6001600160a01b038116600081815260036020908152604080832080546000190190558583526002825280832080546001600160a01b031990811690915560049092528083208054909216909155518492907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908390a45050565b6001600160a01b03821661313c5760405162461bcd60e51b81526020600482015260116024820152701253959053125117d49150d25412515395607a1b6044820152606401610d8e565b6000818152600260205260409020546001600160a01b0316156131925760405162461bcd60e51b815260206004820152600e60248201526d1053149150511657d3525395115160921b6044820152606401610d8e565b6001600160a01b038216600081815260036020908152604080832080546001019055848352600290915280822080546001600160a01b0319168417905551839291907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a45050565b6001600160e01b0319811681146114b057600080fd5b60006020828403121561322557600080fd5b8135611291816131fd565b60005b8381101561324b578181015183820152602001613233565b50506000910152565b6020815260008251806020840152613273816040850160208701613230565b601f01601f19169190910160400192915050565b60006020828403121561329957600080fd5b5035919050565b6001600160a01b03811681146114b057600080fd5b600080604083850312156132c857600080fd5b82356132d3816132a0565b946020939093013593505050565b6000806000606084860312156132f657600080fd5b8335613301816132a0565b92506020840135613311816132a0565b929592945050506040919091013590565b60006020828403121561333457600080fd5b8135611291816132a0565b6001600160401b03811681146114b057600080fd5b60006020828403121561336657600080fd5b81356112918161333f565b60008083601f84011261338357600080fd5b5081356001600160401b0381111561339a57600080fd5b6020830191508360208260051b85010111156133b557600080fd5b9250929050565b6000806000604084860312156133d157600080fd5b83356001600160401b038111156133e757600080fd5b6133f386828701613371565b9094509250506020840135613407816132a0565b809150509250925092565b80151581146114b057600080fd5b60008060006060848603121561343557600080fd5b833561344081613412565b9250602084013561331181613412565b60006020828403121561346257600080fd5b81356001600160801b038116811461129157600080fd5b60008083601f84011261348b57600080fd5b5081356001600160401b038111156134a257600080fd5b6020830191508360208285010111156133b557600080fd5b600080602083850312156134cd57600080fd5b82356001600160401b038111156134e357600080fd5b6134ef85828601613479565b90969095509350505050565b60008060006040848603121561351057600080fd5b83356001600160401b0381111561352657600080fd5b61353286828701613371565b909790965060209590950135949350505050565b6000806040838503121561355957600080fd5b8235613564816132a0565b9150602083013561357481613412565b809150509250929050565b60008060008060006080868803121561359757600080fd5b85356135a2816132a0565b945060208601356135b2816132a0565b93506040860135925060608601356001600160401b038111156135d457600080fd5b6135e088828901613479565b969995985093965092949392505050565b60006020828403121561360357600080fd5b813561129181613412565b6000806040838503121561362157600080fd5b823561362c816132a0565b91506020830135613574816132a0565b600181811c9082168061365057607f821691505b60208210810361367057634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052601160045260246000fd5b80820180821115610c7857610c78613676565b6000602082840312156136b157600080fd5b8151611291816131fd565b634e487b7160e01b600052604160045260246000fd5b601f821115610f8057600081815260208120601f850160051c810160208610156136f95750805b601f850160051c820191505b818110156122c757828155600101613705565b6001600160401b0383111561372f5761372f6136bc565b6137438361373d835461363c565b836136d2565b6000601f841160018114613777576000851561375f5750838201355b600019600387901b1c1916600186901b178355611aea565b600083815260209020601f19861690835b828110156137a85786850135825560209485019460019092019101613788565b50868210156137c55760001960f88860031b161c19848701351681555b505060018560011b0183555050505050565b60006020808352600084546137eb8161363c565b8084870152604060018084166000811461380c576001811461382657613854565b60ff1985168984015283151560051b890183019550613854565b896000528660002060005b8581101561384c5781548b8201860152908301908801613831565b8a0184019650505b509398975050505050505050565b81810381811115610c7857610c78613676565b634e487b7160e01b600052603260045260246000fd5b8082028115828204841417610c7857610c78613676565b6000826138bf57634e487b7160e01b600052601260045260246000fd5b500490565b6001600160a01b038681168252851660208201526040810184905260806060820181905281018290526000828460a0840137600060a0848401015260a0601f19601f85011683010190509695505050505050565b6000835161392a818460208801613230565b83519083019061393e818360208801613230565b64173539b7b760d91b9101908152600501949350505050565b60008060006060848603121561396c57600080fd5b83516139778161333f565b60208501519093506139888161333f565b60408501519092506134078161333f565b6001600160401b038181168382160280821691908281146139bc576139bc613676565b505092915050565b6001600160401b038181168382160190808211156139e4576139e4613676565b5092915050565b604051601f8201601f191681016001600160401b0381118282101715613a1357613a136136bc565b604052919050565b60006020808385031215613a2e57600080fd5b82516001600160401b0380821115613a4557600080fd5b818501915085601f830112613a5957600080fd5b815181811115613a6b57613a6b6136bc565b8060051b9150613a7c8483016139eb565b8181529183018401918481019088841115613a9657600080fd5b938501935b83851015613ab457845182529385019390850190613a9b565b98975050505050505050565b600060608284031215613ad257600080fd5b604051606081018181106001600160401b0382111715613af457613af46136bc565b6040528251613b0281613412565b8152602083015160ff81168114613b1857600080fd5b6020820152604083015162ffffff81168114613b3357600080fd5b60408201529392505050565b600080600060608486031215613b5457600080fd5b835192506020840151613b66816132a0565b80925050604084015190509250925092565b600060018201613b8a57613b8a613676565b5060010190565b60006001600160801b03821680613baa57613baa613676565b6000190192915050565b6001600160401b038281168282160390808211156139e4576139e4613676565b60006001600160801b03808316818103613bf057613bf0613676565b6001019392505050565b600060208284031215613c0c57600080fd5b8151611291816132a056fea2646970667358221220d89063dda8c1849b792890900b569e220384c433db58c6e6223685c6dfeec3a064736f6c63430008110033

Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)

0000000000000000000000001fec856e25f757fed06eb90548b0224e910957380000000000000000000000002cfbcb9e9c3d1ab06ef332f535266444aa8d9570000000000000000000000000053d938a4d2a6df86d837d66a037444d7bacf3b90000000000000000000000003c43e86c4c3ba4d2b6c15439d2d97556985814a2000000000000000000000000b7ccb0ee5c06562282048f95e27c73b148dcb6d20000000000000000000000002630ef1e79e38ec1e42db2a891ce1b62542a236200000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000002168747470733a2f2f70756e6b732e33646672616e6b656e70756e6b732e636f6d2f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005168747470733a2f2f676174657761792e70696e6174612e636c6f75642f697066732f516d53464e765a466d5367766b65425a6150646f48586e55346e364243694b783734776257636a376245466153742f000000000000000000000000000000

-----Decoded View---------------
Arg [0] : _frankenpunks (address): 0x1FEC856e25F757FeD06eB90548B0224E91095738
Arg [1] : _frankenmonsters (address): 0x2cfBCB9e9C3D1ab06eF332f535266444aa8d9570
Arg [2] : _governance (address): 0x053d938a4d2A6DF86D837D66a037444D7bACF3B9
Arg [3] : _executor (address): 0x3c43e86C4C3ba4D2b6C15439D2d97556985814a2
Arg [4] : _founders (address): 0xb7cCB0Ee5C06562282048F95e27C73b148Dcb6d2
Arg [5] : _council (address): 0x2630eF1E79E38Ec1E42db2a891CE1b62542A2362
Arg [6] : _baseTokenURI (string): https://punks.3dfrankenpunks.com/
Arg [7] : _contractURI (string): https://gateway.pinata.cloud/ipfs/QmSFNvZFmSgvkeBZaPdoHXnU4n6BCiKx74wbWcj7bEFaSt/

-----Encoded View---------------
15 Constructor Arguments found :
Arg [0] : 0000000000000000000000001fec856e25f757fed06eb90548b0224e91095738
Arg [1] : 0000000000000000000000002cfbcb9e9c3d1ab06ef332f535266444aa8d9570
Arg [2] : 000000000000000000000000053d938a4d2a6df86d837d66a037444d7bacf3b9
Arg [3] : 0000000000000000000000003c43e86c4c3ba4d2b6c15439d2d97556985814a2
Arg [4] : 000000000000000000000000b7ccb0ee5c06562282048f95e27c73b148dcb6d2
Arg [5] : 0000000000000000000000002630ef1e79e38ec1e42db2a891ce1b62542a2362
Arg [6] : 0000000000000000000000000000000000000000000000000000000000000100
Arg [7] : 0000000000000000000000000000000000000000000000000000000000000160
Arg [8] : 0000000000000000000000000000000000000000000000000000000000000021
Arg [9] : 68747470733a2f2f70756e6b732e33646672616e6b656e70756e6b732e636f6d
Arg [10] : 2f00000000000000000000000000000000000000000000000000000000000000
Arg [11] : 0000000000000000000000000000000000000000000000000000000000000051
Arg [12] : 68747470733a2f2f676174657761792e70696e6174612e636c6f75642f697066
Arg [13] : 732f516d53464e765a466d5367766b65425a6150646f48586e55346e36424369
Arg [14] : 4b783734776257636a376245466153742f000000000000000000000000000000


Loading...
Loading
Loading...
Loading
[ Download: CSV Export  ]

A token is a representation of an on-chain or off-chain asset. The token page shows information such as price, total supply, holders, transfers and social links. Learn more about this page in our Knowledge Base.