ETH Price: $3,391.44 (+1.24%)
Gas: 8 Gwei

Contract

0x37a0a06F00d22F945D972090dddaBd981988a2e8
 

Overview

ETH Balance

3.876205544181460043 ETH

Eth Value

$13,145.91 (@ $3,391.44/ETH)

Token Holdings

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Delegate201813672024-06-27 6:55:1119 days ago1719471311IN
FrankenDAO: Staking
0 ETH0.000232924.03481577
Delegate201813642024-06-27 6:54:3519 days ago1719471275IN
FrankenDAO: Staking
0 ETH0.000482263.86316224
Unstake201491682024-06-22 18:55:5923 days ago1719082559IN
FrankenDAO: Staking
0 ETH0.000361432.41345909
Unstake201203672024-06-18 18:15:4727 days ago1718734547IN
FrankenDAO: Staking
0 ETH0.0007036.85265117
Stake201049462024-06-16 14:26:5929 days ago1718548019IN
FrankenDAO: Staking
0 ETH0.00113164.17940029
Stake200359752024-06-06 23:09:3539 days ago1717715375IN
FrankenDAO: Staking
0 ETH0.0046563817.19695026
Stake200137362024-06-03 20:39:5942 days ago1717447199IN
FrankenDAO: Staking
0 ETH0.0025987114.53727798
Delegate200132212024-06-03 18:55:5942 days ago1717440959IN
FrankenDAO: Staking
0 ETH0.003192115.06086321
Set Pause199950392024-06-01 6:00:2345 days ago1717221623IN
FrankenDAO: Staking
0 ETH0.000177546.04563718
Set Pause199592802024-05-27 6:00:2350 days ago1716789623IN
FrankenDAO: Staking
0 ETH0.000406597.92882472
Set Pause199449602024-05-25 6:00:2352 days ago1716616823IN
FrankenDAO: Staking
0 ETH0.000146865.00092047
Set Pause199092102024-05-20 6:00:2357 days ago1716184823IN
FrankenDAO: Staking
0 ETH0.000213634.1660672
Delegate198996272024-05-18 21:51:3558 days ago1716069095IN
FrankenDAO: Staking
0 ETH0.000692383.06044955
Set Pause198949082024-05-18 6:00:2359 days ago1716012023IN
FrankenDAO: Staking
0 ETH0.000141574.82067342
Set Pause198591642024-05-13 6:00:2364 days ago1715580023IN
FrankenDAO: Staking
0 ETH0.00027875.43487015
Set Pause198448632024-05-11 6:00:2366 days ago1715407223IN
FrankenDAO: Staking
0 ETH0.000179776.12145993
Set Pause198091202024-05-06 6:00:2371 days ago1714975223IN
FrankenDAO: Staking
0 ETH0.000281345.48650761
Set Pause197948122024-05-04 6:00:2373 days ago1714802423IN
FrankenDAO: Staking
0 ETH0.000194666.62834643
Set Pause197590422024-04-29 6:00:2378 days ago1714370423IN
FrankenDAO: Staking
0 ETH0.000407197.94055284
Set Pause197447482024-04-27 6:00:2380 days ago1714197623IN
FrankenDAO: Staking
0 ETH0.00020867.10325336
Set Pause197090122024-04-22 6:00:2385 days ago1713765623IN
FrankenDAO: Staking
0 ETH0.00040547.90567797
Stake197077212024-04-22 1:40:4785 days ago1713750047IN
FrankenDAO: Staking
0 ETH0.002965355.4858959
Set Pause196947012024-04-20 6:00:2387 days ago1713592823IN
FrankenDAO: Staking
0 ETH0.000247028.41138596
Set Approval For...196589952024-04-15 6:01:1192 days ago1713160871IN
FrankenDAO: Staking
0 ETH0.000363597.88203107
Stake196589932024-04-15 6:00:4792 days ago1713160847IN
FrankenDAO: Staking
0 ETH0.000248988.03887927
View all transactions

Latest 25 internal transactions (View All)

Advanced mode:
Parent Transaction Hash Block From To
201813642024-06-27 6:54:3519 days ago1719471275
FrankenDAO: Staking
0.00046116 ETH
201049462024-06-16 14:26:5929 days ago1718548019
FrankenDAO: Staking
0.00108711 ETH
200359752024-06-06 23:09:3539 days ago1717715375
FrankenDAO: Staking
0.00434324 ETH
200137362024-06-03 20:39:5942 days ago1717447199
FrankenDAO: Staking
0.00235989 ETH
200132212024-06-03 18:55:5942 days ago1717440959
FrankenDAO: Staking
0.00300659 ETH
198996272024-05-18 21:51:3558 days ago1716069095
FrankenDAO: Staking
0.00067567 ETH
197077212024-04-22 1:40:4785 days ago1713750047
FrankenDAO: Staking
0.00295711 ETH
196589482024-04-15 5:51:4792 days ago1713160307
FrankenDAO: Staking
0.00223458 ETH
196589442024-04-15 5:50:5992 days ago1713160259
FrankenDAO: Staking
0.00329678 ETH
195981452024-04-06 17:21:59100 days ago1712424119
FrankenDAO: Staking
0.00277327 ETH
193024652024-02-25 5:19:11142 days ago1708838351
FrankenDAO: Staking
0.00662708 ETH
192595472024-02-19 4:55:35148 days ago1708318535
FrankenDAO: Staking
0.02444327 ETH
191071632024-01-28 19:37:23169 days ago1706470643
FrankenDAO: Staking
0.00353403 ETH
190970032024-01-27 9:24:11171 days ago1706347451
FrankenDAO: Staking
0.03475415 ETH
190540382024-01-21 8:26:59177 days ago1705825619
FrankenDAO: Staking
0.00316194 ETH
190012672024-01-13 23:31:35184 days ago1705188695
FrankenDAO: Staking
0.00425899 ETH
188971942023-12-30 8:36:47199 days ago1703925407
FrankenDAO: Staking
0.01149295 ETH
187576712023-12-10 18:43:35218 days ago1702233815
FrankenDAO: Staking
0.04079911 ETH
186538192023-11-26 5:39:47233 days ago1700977187
FrankenDAO: Staking
0.00434879 ETH
186499602023-11-25 16:40:23233 days ago1700930423
FrankenDAO: Staking
0.01622148 ETH
186102382023-11-20 3:12:23239 days ago1700449943
FrankenDAO: Staking
0.00530726 ETH
186050062023-11-19 9:36:47239 days ago1700386607
FrankenDAO: Staking
0.00573199 ETH
186044892023-11-19 7:52:59240 days ago1700380379
FrankenDAO: Staking
0.04543881 ETH
186021392023-11-18 23:58:59240 days ago1700351939
FrankenDAO: Staking
0.00332081 ETH
185092232023-11-05 23:58:11253 days ago1699228691
FrankenDAO: Staking
0.00503641 ETH
View All Internal Transactions
Loading...
Loading

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


Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

OVERVIEW

The staking contract for FrankenDAO.

Validator Index Block Amount
View All Withdrawals

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

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