ETH Price: $3,402.73 (+2.61%)

Contract

0x52010E220E5C8eF2217D86cfA58da51Da39e8ec4
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To

There are no matching entries

Please try again later

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
Party

Compiler Version
v0.8.17+commit.8df45f5f

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion
File 1 of 30 : Party.sol
// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.17;

import "../tokens/IERC721.sol";

import "./PartyGovernanceNFT.sol";
import "./PartyGovernance.sol";

/// @notice The governance contract that also custodies the precious NFTs. This
///         is also the Governance NFT 721 contract.
contract Party is PartyGovernanceNFT {
    // Arguments used to initialize the party.
    struct PartyOptions {
        PartyGovernance.GovernanceOpts governance;
        string name;
        string symbol;
        uint256 customizationPresetId;
    }

    // Arguments used to initialize the `PartyGovernanceNFT`.
    struct PartyInitData {
        PartyOptions options;
        IERC721[] preciousTokens;
        uint256[] preciousTokenIds;
        address mintAuthority;
    }

    // Set the `Globals` contract.
    constructor(IGlobals globals) PartyGovernanceNFT(globals) {}

    /// @notice Initializer to be delegatecalled by `Proxy` constructor. Will
    ///         revert if called outside the constructor.
    /// @param initData Options used to initialize the party governance.
    function initialize(PartyInitData memory initData)
        external
        onlyConstructor
    {
        PartyGovernanceNFT._initialize(
            initData.options.name,
            initData.options.symbol,
            initData.options.customizationPresetId,
            initData.options.governance,
            initData.preciousTokens,
            initData.preciousTokenIds,
            initData.mintAuthority
        );
    }

    receive() external payable {}
}

File 2 of 30 : ITokenDistributor.sol
// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.17;

import "../tokens/IERC20.sol";

import "./ITokenDistributorParty.sol";

/// @notice Creates token distributions for parties.
interface ITokenDistributor {
    enum TokenType {
        Native,
        Erc20
    }

    // Info on a distribution, created by createDistribution().
    struct DistributionInfo {
        // Type of distribution/token.
        TokenType tokenType;
        // ID of the distribution. Assigned by createDistribution().
        uint256 distributionId;
        // The party whose members can claim the distribution.
        ITokenDistributorParty party;
        // Who can claim `fee`.
        address payable feeRecipient;
        // The token being distributed.
        address token;
        // Total amount of `token` that can be claimed by party members.
        uint128 memberSupply;
        // Amount of `token` to be redeemed by `feeRecipient`.
        uint128 fee;
    }

    event DistributionCreated(
        ITokenDistributorParty indexed party,
        DistributionInfo info
    );
    event DistributionFeeClaimed(
        ITokenDistributorParty indexed party,
        address indexed feeRecipient,
        TokenType tokenType,
        address token,
        uint256 amount
    );
    event DistributionClaimedByPartyToken(
        ITokenDistributorParty indexed party,
        uint256 indexed partyTokenId,
        address indexed owner,
        TokenType tokenType,
        address token,
        uint256 amountClaimed
    );

    /// @notice Create a new distribution for an outstanding native token balance
    ///         governed by a party.
    /// @dev Native tokens should be transferred directly into this contract
    ///      immediately prior (same tx) to calling `createDistribution()` or
    ///      attached to the call itself.
    /// @param party The party whose members can claim the distribution.
    /// @param feeRecipient Who can claim `fee`.
    /// @param feeBps Percentage (in bps) of the distribution `feeRecipient` receives.
    /// @return info Information on the created distribution.
    function createNativeDistribution(
        ITokenDistributorParty party,
        address payable feeRecipient,
        uint16 feeBps
    )
        external
        payable
        returns (DistributionInfo memory info);

    /// @notice Create a new distribution for an outstanding ERC20 token balance
    ///         governed by a party.
    /// @dev ERC20 tokens should be transferred directly into this contract
    ///      immediately prior (same tx) to calling `createDistribution()` or
    ///      attached to the call itself.
    /// @param token The ERC20 token to distribute.
    /// @param party The party whose members can claim the distribution.
    /// @param feeRecipient Who can claim `fee`.
    /// @param feeBps Percentage (in bps) of the distribution `feeRecipient` receives.
    /// @return info Information on the created distribution.
    function createErc20Distribution(
        IERC20 token,
        ITokenDistributorParty party,
        address payable feeRecipient,
        uint16 feeBps
    )
        external
        returns (DistributionInfo memory info);

    /// @notice Claim a portion of a distribution owed to a `partyTokenId` belonging
    ///         to the party that created the distribution. The caller
    ///         must own this token.
    /// @param info Information on the distribution being claimed.
    /// @param partyTokenId The ID of the party token to claim for.
    /// @return amountClaimed The amount of the distribution claimed.
    function claim(DistributionInfo calldata info, uint256 partyTokenId)
        external
        returns (uint128 amountClaimed);

    /// @notice Claim the fee for a distribution. Only a distribution's `feeRecipient`
    ///         can call this.
    /// @param info Information on the distribution being claimed.
    /// @param recipient The address to send the fee to.
    function claimFee(DistributionInfo calldata info, address payable recipient)
        external;

    /// @notice Batch version of `claim()`.
    /// @param infos Information on the distributions being claimed.
    /// @param partyTokenIds The ID of the party tokens to claim for.
    /// @return amountsClaimed The amount of the distributions claimed.
    function batchClaim(DistributionInfo[] calldata infos, uint256[] calldata partyTokenIds)
        external
        returns (uint128[] memory amountsClaimed);

    /// @notice Batch version of `claimFee()`.
    /// @param infos Information on the distributions to claim fees for.
    /// @param recipients The addresses to send the fees to.
    function batchClaimFee(DistributionInfo[] calldata infos, address payable[] calldata recipients)
        external;

    /// @notice Compute the amount of a distribution's token are owed to a party
    ///         member, identified by the `partyTokenId`.
    /// @param party The party to use for computing the claim amount.
    /// @param memberSupply Total amount of tokens that can be claimed in the distribution.
    /// @param partyTokenId The ID of the party token to claim for.
    /// @return claimAmount The amount of the distribution owed to the party member.
    function getClaimAmount(
        ITokenDistributorParty party,
        uint256 memberSupply,
        uint256 partyTokenId
    )
        external
        view
        returns (uint128);

    /// @notice Check whether the fee has been claimed for a distribution.
    /// @param party The party to use for checking whether the fee has been claimed.
    /// @param distributionId The ID of the distribution to check.
    /// @return feeClaimed Whether the fee has been claimed.
    function wasFeeClaimed(ITokenDistributorParty party, uint256 distributionId)
        external
        view
        returns (bool);

    /// @notice Check whether a `partyTokenId` has claimed their share of a distribution.
    /// @param party The party to use for checking whether the `partyTokenId` has claimed.
    /// @param partyTokenId The ID of the party token to check.
    /// @param distributionId The ID of the distribution to check.
    /// @return hasClaimed Whether the `partyTokenId` has claimed.
    function hasPartyTokenIdClaimed(
        ITokenDistributorParty party,
        uint256 partyTokenId,
        uint256 distributionId
    )
        external
        view returns (bool);

    /// @notice Get how much unclaimed member tokens are left in a distribution.
    /// @param party The party to use for checking the unclaimed member tokens.
    /// @param distributionId The ID of the distribution to check.
    /// @return remainingMemberSupply The amount of distribution supply remaining.
    function getRemainingMemberSupply(
        ITokenDistributorParty party,
        uint256 distributionId
    )
        external
        view
        returns (uint128);
}

File 3 of 30 : ITokenDistributorParty.sol
// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.17;

// Interface the caller of `ITokenDistributor.createDistribution()` must implement.
interface ITokenDistributorParty {
    /// @notice Return the owner of a token.
    /// @param tokenId The token ID to query.
    /// @return owner The owner of `tokenId`.
    function ownerOf(uint256 tokenId) external view returns (address);
    /// @notice Return the distribution share of a token. Denominated fractions
    ///         of 1e18. I.e., 1e18 = 100%.
    /// @param tokenId The token ID to query.
    /// @return share The distribution percentage of `tokenId`.
    function getDistributionShareOf(uint256 tokenId) external view returns (uint256);
}

File 4 of 30 : IGlobals.sol
// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.17;

import "../utils/Implementation.sol";

// Single registry of global values controlled by multisig.
// See `LibGlobals` for all valid keys.
interface IGlobals {
    function getBytes32(uint256 key) external view returns (bytes32);
    function getUint256(uint256 key) external view returns (uint256);
    function getBool(uint256 key) external view returns (bool);
    function getAddress(uint256 key) external view returns (address);
    function getImplementation(uint256 key) external view returns (Implementation);
    function getIncludesBytes32(uint256 key, bytes32 value) external view returns (bool);
    function getIncludesUint256(uint256 key, uint256 value) external view returns (bool);
    function getIncludesAddress(uint256 key, address value) external view returns (bool);

    function setBytes32(uint256 key, bytes32 value) external;
    function setUint256(uint256 key, uint256 value) external;
    function setBool(uint256 key, bool value) external;
    function setAddress(uint256 key, address value) external;
    function setIncludesBytes32(uint256 key, bytes32 value, bool isIncluded) external;
    function setIncludesUint256(uint256 key, uint256 value, bool isIncluded) external;
    function setIncludesAddress(uint256 key, address value, bool isIncluded) external;
}

File 5 of 30 : LibGlobals.sol
// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.17;

// Valid keys in `IGlobals`. Append-only.
library LibGlobals {
    uint256 internal constant GLOBAL_PARTY_IMPL                     = 1;
    uint256 internal constant GLOBAL_PROPOSAL_ENGINE_IMPL           = 2;
    uint256 internal constant GLOBAL_PARTY_FACTORY                  = 3;
    uint256 internal constant GLOBAL_GOVERNANCE_NFT_RENDER_IMPL     = 4;
    uint256 internal constant GLOBAL_CF_NFT_RENDER_IMPL             = 5;
    uint256 internal constant GLOBAL_OS_ZORA_AUCTION_TIMEOUT        = 6;
    uint256 internal constant GLOBAL_OS_ZORA_AUCTION_DURATION       = 7;
    uint256 internal constant GLOBAL_AUCTION_CF_IMPL                = 8;
    uint256 internal constant GLOBAL_BUY_CF_IMPL                    = 9;
    uint256 internal constant GLOBAL_COLLECTION_BUY_CF_IMPL         = 10;
    uint256 internal constant GLOBAL_DAO_WALLET                     = 11;
    uint256 internal constant GLOBAL_TOKEN_DISTRIBUTOR              = 12;
    uint256 internal constant GLOBAL_OPENSEA_CONDUIT_KEY            = 13;
    uint256 internal constant GLOBAL_OPENSEA_ZONE                   = 14;
    uint256 internal constant GLOBAL_PROPOSAL_MAX_CANCEL_DURATION   = 15;
    uint256 internal constant GLOBAL_ZORA_MIN_AUCTION_DURATION      = 16;
    uint256 internal constant GLOBAL_ZORA_MAX_AUCTION_DURATION      = 17;
    uint256 internal constant GLOBAL_ZORA_MAX_AUCTION_TIMEOUT       = 18;
    uint256 internal constant GLOBAL_OS_MIN_ORDER_DURATION          = 19;
    uint256 internal constant GLOBAL_OS_MAX_ORDER_DURATION          = 20;
    uint256 internal constant GLOBAL_DISABLE_PARTY_ACTIONS          = 21;
    uint256 internal constant GLOBAL_RENDERER_STORAGE               = 22;
    uint256 internal constant GLOBAL_PROPOSAL_MIN_CANCEL_DURATION   = 23;
}

File 6 of 30 : IPartyFactory.sol
// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.17;

import "../globals/IGlobals.sol";
import "../tokens/IERC721.sol";

import "./Party.sol";

// Creates generic Party instances.
interface IPartyFactory {
    event PartyCreated(
        Party indexed party,
        Party.PartyOptions opts,
        IERC721[] preciousTokens,
        uint256[] preciousTokenIds,
        address creator
    );

    /// @notice Deploy a new party instance. Afterwards, governance NFTs can be minted
    ///         for party members using the `mint()` function from the newly
    ///         created party.
    /// @param authority The address that can call `mint()`.
    /// @param opts Options used to initialize the party. These are fixed
    ///             and cannot be changed later.
    /// @param preciousTokens The tokens that are considered precious by the
    ///                       party.These are protected assets and are subject
    ///                       to extra restrictions in proposals vs other
    ///                       assets.
    /// @param preciousTokenIds The IDs associated with each token in `preciousTokens`.
    /// @return party The newly created `Party` instance.
    function createParty(
        address authority,
        Party.PartyOptions calldata opts,
        IERC721[] memory preciousTokens,
        uint256[] memory preciousTokenIds
    )
        external
        returns (Party party);

    /// @notice The `Globals` contract storing global configuration values. This contract
    ///         is immutable and it’s address will never change.
    function GLOBALS() external view returns (IGlobals);
}

File 7 of 30 : PartyGovernance.sol
// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.17;

import "../distribution/ITokenDistributorParty.sol";
import "../distribution/ITokenDistributor.sol";
import "../utils/ReadOnlyDelegateCall.sol";
import "../tokens/IERC721.sol";
import "../tokens/IERC20.sol";
import "../tokens/IERC1155.sol";
import "../tokens/ERC721Receiver.sol";
import "../tokens/ERC1155Receiver.sol";
import "../utils/LibERC20Compat.sol";
import "../utils/LibRawResult.sol";
import "../utils/LibSafeCast.sol";
import "../globals/IGlobals.sol";
import "../globals/LibGlobals.sol";
import "../proposals/IProposalExecutionEngine.sol";
import "../proposals/LibProposal.sol";
import "../proposals/ProposalStorage.sol";

import "./IPartyFactory.sol";

/// @notice Base contract for a Party encapsulating all governance functionality.
abstract contract PartyGovernance is
    ITokenDistributorParty,
    ERC721Receiver,
    ERC1155Receiver,
    ProposalStorage,
    Implementation,
    ReadOnlyDelegateCall
{
    using LibERC20Compat for IERC20;
    using LibRawResult for bytes;
    using LibSafeCast for uint256;
    using LibSafeCast for int192;
    using LibSafeCast for uint96;

    // States a proposal can be in.
    enum ProposalStatus {
        // The proposal does not exist.
        Invalid,
        // The proposal has been proposed (via `propose()`), has not been vetoed
        // by a party host, and is within the voting window. Members can vote on
        // the proposal and party hosts can veto the proposal.
        Voting,
        // The proposal has either exceeded its voting window without reaching
        // `passThresholdBps` of votes or was vetoed by a party host.
        Defeated,
        // The proposal reached at least `passThresholdBps` of votes but is still
        // waiting for `executionDelay` to pass before it can be executed. Members
        // can continue to vote on the proposal and party hosts can veto at this time.
        Passed,
        // Same as `Passed` but now `executionDelay` has been satisfied. Any member
        // may execute the proposal via `execute()`, unless `maxExecutableTime`
        // has arrived.
        Ready,
        // The proposal has been executed at least once but has further steps to
        // complete so it needs to be executed again. No other proposals may be
        // executed while a proposal is in the `InProgress` state. No voting or
        // vetoing of the proposal is allowed, however it may be forcibly cancelled
        // via `cancel()` if the `cancelDelay` has passed since being first executed.
        InProgress,
        // The proposal was executed and completed all its steps. No voting or
        // vetoing can occur and it cannot be cancelled nor executed again.
        Complete,
        // The proposal was executed at least once but did not complete before
        // `cancelDelay` seconds passed since the first execute and was forcibly cancelled.
        Cancelled
    }

    struct GovernanceOpts {
        // Address of initial party hosts.
        address[] hosts;
        // How long people can vote on a proposal.
        uint40 voteDuration;
        // How long to wait after a proposal passes before it can be
        // executed.
        uint40 executionDelay;
        // Minimum ratio of accept votes to consider a proposal passed,
        // in bps, where 10,000 == 100%.
        uint16 passThresholdBps;
        // Total voting power of governance NFTs.
        uint96 totalVotingPower;
        // Fee bps for distributions.
        uint16 feeBps;
        // Fee recipeint for distributions.
        address payable feeRecipient;
    }

    // Subset of `GovernanceOpts` that are commonly read together for
    // efficiency.
    struct GovernanceValues {
        uint40 voteDuration;
        uint40 executionDelay;
        uint16 passThresholdBps;
        uint96 totalVotingPower;
    }

    // A snapshot of voting power for a member.
    struct VotingPowerSnapshot {
        // The timestamp when the snapshot was taken.
        uint40 timestamp;
        // Voting power that was delegated to this user by others.
        uint96 delegatedVotingPower;
        // The intrinsic (not delegated from someone else) voting power of this user.
        uint96 intrinsicVotingPower;
        // Whether the user was delegated to another at this snapshot.
        bool isDelegated;
    }

    // Proposal details chosen by proposer.
    struct Proposal {
        // Time beyond which the proposal can no longer be executed.
        // If the proposal has already been executed, and is still InProgress,
        // this value is ignored.
        uint40 maxExecutableTime;
        // The minimum seconds this proposal can remain in the InProgress status
        // before it can be cancelled.
        uint40 cancelDelay;
        // Encoded proposal data. The first 4 bytes are the proposal type, followed
        // by encoded proposal args specific to the proposal type. See
        // ProposalExecutionEngine for details.
        bytes proposalData;
    }

    // Accounting and state tracking values for a proposal.
    // Fits in a word.
    struct ProposalStateValues {
        // When the proposal was proposed.
        uint40 proposedTime;
        // When the proposal passed the vote.
        uint40 passedTime;
        // When the proposal was first executed.
        uint40 executedTime;
        // When the proposal completed.
        uint40 completedTime;
        // Number of accept votes.
        uint96 votes; // -1 == vetoed
    }

    // Storage states for a proposal.
    struct ProposalState {
        // Accounting and state tracking values.
        ProposalStateValues values;
        // Hash of the proposal.
        bytes32 hash;
        // Whether a member has voted for (accepted) this proposal already.
        mapping (address => bool) hasVoted;
    }

    event Proposed(
        uint256 proposalId,
        address proposer,
        Proposal proposal
    );
    event ProposalAccepted(
        uint256 proposalId,
        address voter,
        uint256 weight
    );
    event EmergencyExecute(address target, bytes data, uint256 amountEth);

    event ProposalPassed(uint256 indexed proposalId);
    event ProposalVetoed(uint256 indexed proposalId, address host);
    event ProposalExecuted(uint256 indexed proposalId, address executor, bytes nextProgressData);
    event ProposalCancelled(uint256 indexed proposalId);
    event DistributionCreated(ITokenDistributor.TokenType tokenType, address token, uint256 tokenId);
    event VotingPowerDelegated(address indexed owner, address indexed delegate);
    event HostStatusTransferred(address oldHost, address newHost);
    event EmergencyExecuteDisabled();

    error MismatchedPreciousListLengths();
    error BadProposalStatusError(ProposalStatus status);
    error BadProposalHashError(bytes32 proposalHash, bytes32 actualHash);
    error ExecutionTimeExceededError(uint40 maxExecutableTime, uint40 timestamp);
    error OnlyPartyHostError();
    error OnlyActiveMemberError();
    error InvalidDelegateError();
    error BadPreciousListError();
    error OnlyPartyDaoError(address notDao, address partyDao);
    error OnlyPartyDaoOrHostError(address notDao, address partyDao);
    error OnlyWhenEmergencyActionsAllowedError();
    error OnlyWhenEnabledError();
    error AlreadyVotedError(address voter);
    error InvalidNewHostError();
    error ProposalCannotBeCancelledYetError(uint40 currentTime, uint40 cancelTime);
    error InvalidBpsError(uint16 bps);

    uint256 constant private UINT40_HIGH_BIT = 1 << 39;
    uint96 constant private VETO_VALUE = type(uint96).max;

    // The `Globals` contract storing global configuration values. This contract
    // is immutable and it’s address will never change.
    IGlobals private immutable _GLOBALS;

    /// @notice Whether the DAO has emergency powers for this party.
    bool public emergencyExecuteDisabled;
    /// @notice Distribution fee bps.
    uint16 public feeBps;
    /// @notice Distribution fee recipient.
    address payable public feeRecipient;
    /// @notice The hash of the list of precious NFTs guarded by the party.
    bytes32 public preciousListHash;
    /// @notice The last proposal ID that was used. 0 means no proposals have been made.
    uint256 public lastProposalId;
    /// @notice Whether an address is a party host.
    mapping(address => bool) public isHost;
    /// @notice The last person a voter delegated its voting power to.
    mapping(address => address) public delegationsByVoter;
    // Constant governance parameters, fixed from the inception of this party.
    GovernanceValues internal _governanceValues;
    // ProposalState by proposal ID.
    mapping(uint256 => ProposalState) private _proposalStateByProposalId;
    // Snapshots of voting power per user, each sorted by increasing time.
    mapping(address => VotingPowerSnapshot[]) private _votingPowerSnapshotsByVoter;

    modifier onlyHost() {
        if (!isHost[msg.sender]) {
            revert OnlyPartyHostError();
        }
        _;
    }

    // Caller must have voting power at the current time.
    modifier onlyActiveMember() {
        {
            VotingPowerSnapshot memory snap =
                _getLastVotingPowerSnapshotForVoter(msg.sender);
            // Must have either delegated voting power or intrinsic voting power.
            if (snap.intrinsicVotingPower == 0 && snap.delegatedVotingPower == 0) {
                revert OnlyActiveMemberError();
            }
        }
        _;
    }

    // Caller must have voting power at the current time or be the `Party` instance.
    modifier onlyActiveMemberOrSelf() {
        // Ignore if the party is calling functions on itself, like with
        // `FractionalizeProposal` calling `distribute()`.
        if (msg.sender != address(this)) {
            VotingPowerSnapshot memory snap =
                _getLastVotingPowerSnapshotForVoter(msg.sender);
            // Must have either delegated voting power or intrinsic voting power.
            if (snap.intrinsicVotingPower == 0 && snap.delegatedVotingPower == 0) {
                revert OnlyActiveMemberError();
            }
        }
        _;
    }

    // Only the party DAO multisig can call.
    modifier onlyPartyDao() {
        {
            address partyDao = _GLOBALS.getAddress(LibGlobals.GLOBAL_DAO_WALLET);
            if (msg.sender != partyDao) {
                revert OnlyPartyDaoError(msg.sender, partyDao);
            }
        }
        _;
    }

    // Only the party DAO multisig or a party host can call.
    modifier onlyPartyDaoOrHost() {
        address partyDao = _GLOBALS.getAddress(LibGlobals.GLOBAL_DAO_WALLET);
        if (msg.sender != partyDao && !isHost[msg.sender]) {
            revert OnlyPartyDaoOrHostError(msg.sender, partyDao);
        }
        _;
    }

    // Only if `emergencyExecuteDisabled` is not true.
    modifier onlyWhenEmergencyExecuteAllowed() {
        if (emergencyExecuteDisabled) {
            revert OnlyWhenEmergencyActionsAllowedError();
        }
        _;
    }

    modifier onlyWhenNotGloballyDisabled() {
        if (_GLOBALS.getBool(LibGlobals.GLOBAL_DISABLE_PARTY_ACTIONS)) {
            revert OnlyWhenEnabledError();
        }
        _;
    }

    // Set the `Globals` contract.
    constructor(IGlobals globals) {
        _GLOBALS = globals;
    }

    // Initialize storage for proxy contracts and initialize the proposal execution engine.
    function _initialize(
        GovernanceOpts memory opts,
        IERC721[] memory preciousTokens,
        uint256[] memory preciousTokenIds
    )
        internal
        virtual
    {
        // Check BPS are valid.
        if (opts.feeBps > 1e4) {
            revert InvalidBpsError(opts.feeBps);
        }
        if (opts.passThresholdBps > 1e4) {
            revert InvalidBpsError(opts.passThresholdBps);
        }
        // Initialize the proposal execution engine.
        _initProposalImpl(
            IProposalExecutionEngine(
                _GLOBALS.getAddress(LibGlobals.GLOBAL_PROPOSAL_ENGINE_IMPL)
            ),
            ""
        );
        // Set the governance parameters.
        _governanceValues = GovernanceValues({
            voteDuration: opts.voteDuration,
            executionDelay: opts.executionDelay,
            passThresholdBps: opts.passThresholdBps,
            totalVotingPower: opts.totalVotingPower
        });
        // Set fees.
        feeBps = opts.feeBps;
        feeRecipient = opts.feeRecipient;
        // Set the precious list.
        _setPreciousList(preciousTokens, preciousTokenIds);
        // Set the party hosts.
        for (uint256 i=0; i < opts.hosts.length; ++i) {
            isHost[opts.hosts[i]] = true;
        }
    }

    /// @dev Forward all unknown read-only calls to the proposal execution engine.
    ///      Initial use case is to facilitate eip-1271 signatures.
    fallback() external {
        _readOnlyDelegateCall(
            address(_getProposalExecutionEngine()),
            msg.data
        );
    }

    /// @inheritdoc EIP165
    /// @dev Combined logic for `ERC721Receiver` and `ERC1155Receiver`.
    function supportsInterface(bytes4 interfaceId)
        public
        override(ERC721Receiver, ERC1155Receiver)
        virtual
        pure
        returns (bool)
    {
        return ERC721Receiver.supportsInterface(interfaceId) ||
            ERC1155Receiver.supportsInterface(interfaceId);
    }

    /// @notice Get the current `ProposalExecutionEngine` instance.
    function getProposalExecutionEngine()
        external
        view
        returns (IProposalExecutionEngine)
    {
        return _getProposalExecutionEngine();
    }

    /// @notice Get the total voting power of `voter` at a `timestamp`.
    /// @param voter The address of the voter.
    /// @param timestamp The timestamp to get the voting power at.
    /// @return votingPower The total voting power of `voter` at `timestamp`.
    function getVotingPowerAt(address voter, uint40 timestamp)
        external
        view
        returns (uint96 votingPower)
    {
        return getVotingPowerAt(voter, timestamp, type(uint256).max);
    }

    /// @notice Get the total voting power of `voter` at a snapshot `snapIndex`, with checks to
    ///         make sure it is the latest voting snapshot =< `timestamp`.
    /// @param voter The address of the voter.
    /// @param timestamp The timestamp to get the voting power at.
    /// @param snapIndex The index of the snapshot to get the voting power at.
    /// @return votingPower The total voting power of `voter` at `timestamp`.
    function getVotingPowerAt(address voter, uint40 timestamp, uint256 snapIndex)
        public
        view
        returns (uint96 votingPower)
    {
        VotingPowerSnapshot memory snap = _getVotingPowerSnapshotAt(voter, timestamp, snapIndex);
        return (snap.isDelegated ? 0 : snap.intrinsicVotingPower) + snap.delegatedVotingPower;
    }

    /// @notice Get the state of a proposal.
    /// @param proposalId The ID of the proposal.
    /// @return status The status of the proposal.
    /// @return values The state of the proposal.
    function getProposalStateInfo(uint256 proposalId)
        external
        view
        returns (ProposalStatus status, ProposalStateValues memory values)
    {
        values = _proposalStateByProposalId[proposalId].values;
        status = _getProposalStatus(values);
    }

    /// @notice Retrieve fixed governance parameters.
    /// @return gv The governance parameters of this party.
    function getGovernanceValues() external view returns (GovernanceValues memory gv) {
        return _governanceValues;
    }

    /// @notice Get the hash of a proposal.
    /// @dev Proposal details are not stored on-chain so the hash is used to enforce
    ///      consistency between calls.
    /// @param proposal The proposal to hash.
    /// @return proposalHash The hash of the proposal.
    function getProposalHash(Proposal memory proposal)
        public
        pure
        returns (bytes32 proposalHash)
    {
        // Hash the proposal in-place. Equivalent to:
        // keccak256(abi.encode(
        //   proposal.maxExecutableTime,
        //   proposal.cancelDelay,
        //   keccak256(proposal.proposalData)
        // ))
        bytes32 dataHash = keccak256(proposal.proposalData);
        assembly {
            // Overwrite the data field with the hash of its contents and then
            // hash the struct.
            let dataPos := add(proposal, 0x40)
            let t := mload(dataPos)
            mstore(dataPos, dataHash)
            proposalHash := keccak256(proposal, 0x60)
            // Restore the data field.
            mstore(dataPos, t)
        }
    }

    /// @notice Get the index of the most recent voting power snapshot <= `timestamp`.
    /// @param voter The address of the voter.
    /// @param timestamp The timestamp to get the snapshot index at.
    /// @return index The index of the snapshot.
    function findVotingPowerSnapshotIndex(address voter, uint40 timestamp)
        public
        view
        returns (uint256 index)
    {
        VotingPowerSnapshot[] storage snaps = _votingPowerSnapshotsByVoter[voter];

        // Derived from Open Zeppelin binary search
        // ref: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/Checkpoints.sol#L39
        uint256 high = snaps.length;
        uint256 low = 0;
        while (low < high) {
            uint256 mid = (low + high) / 2;
            if (snaps[mid].timestamp > timestamp) {
                // Entry is too recent.
                high = mid;
            } else {
                // Entry is older. This is our best guess for now.
                low = mid + 1;
            }
        }

        // Return `type(uint256).max` if no valid voting snapshots found.
        return high == 0 ? type(uint256).max : high - 1;
    }

    /// @notice Pledge your intrinsic voting power to a new delegate, removing it from
    ///         the old one (if any).
    /// @param delegate The address to delegating voting power to.
    function delegateVotingPower(address delegate) external onlyDelegateCall {
        _adjustVotingPower(msg.sender, 0, delegate);
        emit VotingPowerDelegated(msg.sender, delegate);
    }

    /// @notice Transfer party host status to another.
    /// @param newPartyHost The address of the new host.
    function abdicate(address newPartyHost) external onlyHost onlyDelegateCall {
        // 0 is a special case burn address.
        if (newPartyHost != address(0)) {
            // Cannot transfer host status to an existing host.
            if(isHost[newPartyHost]) {
                revert InvalidNewHostError();
            }
            isHost[newPartyHost] = true;
        }
        isHost[msg.sender] = false;
        emit HostStatusTransferred(msg.sender, newPartyHost);
    }

    /// @notice Create a token distribution by moving the party's entire balance
    ///         to the `TokenDistributor` contract and immediately creating a
    ///         distribution governed by this party.
    /// @dev The `feeBps` and `feeRecipient` this party was created with will be
    ///      propagated to the distribution. Party members are entitled to a
    ///      share of the distribution's tokens proportionate to their relative
    ///      voting power in this party (less the fee).
    /// @dev Allow this to be called by the party itself for `FractionalizeProposal`.
    /// @param tokenType The type of token to distribute.
    /// @param token The address of the token to distribute.
    /// @param tokenId The ID of the token to distribute. Currently unused but
    ///                may be used in the future to support other distribution types.
    /// @return distInfo The information about the created distribution.
    function distribute(
        ITokenDistributor.TokenType tokenType,
        address token,
        uint256 tokenId
    )
        external
        onlyActiveMemberOrSelf
        onlyWhenNotGloballyDisabled
        onlyDelegateCall
        returns (ITokenDistributor.DistributionInfo memory distInfo)
    {
        // Get the address of the token distributor.
        ITokenDistributor distributor = ITokenDistributor(
            _GLOBALS.getAddress(LibGlobals.GLOBAL_TOKEN_DISTRIBUTOR)
        );
        emit DistributionCreated(tokenType, token, tokenId);
        // Create a native token distribution.
        address payable feeRecipient_ = feeRecipient;
        uint16 feeBps_ = feeBps;
        if (tokenType == ITokenDistributor.TokenType.Native) {
            return distributor.createNativeDistribution
                { value: address(this).balance }(this, feeRecipient_, feeBps_);
        }
        // Otherwise must be an ERC20 token distribution.
        assert(tokenType == ITokenDistributor.TokenType.Erc20);
        IERC20(token).compatTransfer(
            address(distributor),
            IERC20(token).balanceOf(address(this))
        );
        return distributor.createErc20Distribution(
            IERC20(token),
            this,
            feeRecipient_,
            feeBps_
        );
    }

    /// @notice Make a proposal for members to vote on and cast a vote to accept it
    ///         as well.
    /// @dev Only an active member (has voting power) can call this.
    ///      Afterwards, members can vote to support it with `accept()` or a party
    ///      host can unilaterally reject the proposal with `veto()`.
    /// @param proposal The details of the proposal.
    /// @param latestSnapIndex The index of the caller's most recent voting power
    ///                        snapshot before the proposal was created. Should
    ///                        be retrieved off-chain and passed in.
    function propose(Proposal memory proposal, uint256 latestSnapIndex)
        external
        onlyActiveMember
        onlyDelegateCall
        returns (uint256 proposalId)
    {
        proposalId = ++lastProposalId;
        // Store the time the proposal was created and the proposal hash.
        (
            _proposalStateByProposalId[proposalId].values,
            _proposalStateByProposalId[proposalId].hash
        ) = (
            ProposalStateValues({
                proposedTime: uint40(block.timestamp),
                passedTime: 0,
                executedTime: 0,
                completedTime: 0,
                votes: 0
            }),
            getProposalHash(proposal)
        );
        emit Proposed(proposalId, msg.sender, proposal);
        accept(proposalId, latestSnapIndex);
    }

    /// @notice Vote to support a proposed proposal.
    /// @dev The voting power cast will be the effective voting power of the caller
    ///      just before `propose()` was called (see `getVotingPowerAt()`).
    ///      If the proposal reaches `passThresholdBps` acceptance ratio then the
    ///      proposal will be in the `Passed` state and will be executable after
    ///      the `executionDelay` has passed, putting it in the `Ready` state.
    /// @param proposalId The ID of the proposal to accept.
    /// @param snapIndex The index of the caller's last voting power snapshot
    ///                  before the proposal was created. Should be retrieved
    ///                  off-chain and passed in.
    /// @return totalVotes The total votes cast on the proposal.
    function accept(uint256 proposalId, uint256 snapIndex)
        public
        onlyDelegateCall
        returns (uint256 totalVotes)
    {
        // Get the information about the proposal.
        ProposalState storage info = _proposalStateByProposalId[proposalId];
        ProposalStateValues memory values = info.values;

        // Can only vote in certain proposal statuses.
        {
            ProposalStatus status = _getProposalStatus(values);
            // Allow voting even if the proposal is passed/ready so it can
            // potentially reach 100% consensus, which unlocks special
            // behaviors for certain proposal types.
            if (
                status != ProposalStatus.Voting &&
                status != ProposalStatus.Passed &&
                status != ProposalStatus.Ready
            ) {
                revert BadProposalStatusError(status);
            }
        }

        // Cannot vote twice.
        if (info.hasVoted[msg.sender]) {
            revert AlreadyVotedError(msg.sender);
        }
        // Mark the caller as having voted.
        info.hasVoted[msg.sender] = true;

        // Increase the total votes that have been cast on this proposal.
        uint96 votingPower = getVotingPowerAt(msg.sender, values.proposedTime - 1, snapIndex);
        values.votes += votingPower;
        info.values = values;
        emit ProposalAccepted(proposalId, msg.sender, votingPower);

        // Update the proposal status if it has reached the pass threshold.
        if (values.passedTime == 0 && _areVotesPassing(
            values.votes,
            _governanceValues.totalVotingPower,
            _governanceValues.passThresholdBps))
        {
            info.values.passedTime = uint40(block.timestamp);
            emit ProposalPassed(proposalId);
        }
        return values.votes;
    }

    /// @notice As a party host, veto a proposal, unilaterally rejecting it.
    /// @dev The proposal will never be executable and cannot be voted on anymore.
    ///      A proposal that has been already executed at least once (in the `InProgress` status)
    ///      cannot be vetoed.
    /// @param proposalId The ID of the proposal to veto.
    function veto(uint256 proposalId) external onlyHost onlyDelegateCall {
        // Setting `votes` to -1 indicates a veto.
        ProposalState storage info = _proposalStateByProposalId[proposalId];
        ProposalStateValues memory values = info.values;

        {
            ProposalStatus status = _getProposalStatus(values);
            // Proposal must be in one of the following states.
            if (
                status != ProposalStatus.Voting &&
                status != ProposalStatus.Passed &&
                status != ProposalStatus.Ready
            ) {
                revert BadProposalStatusError(status);
            }
        }

        // -1 indicates veto.
        info.values.votes = VETO_VALUE;
        emit ProposalVetoed(proposalId, msg.sender);
    }

    /// @notice Executes a proposal that has passed governance.
    /// @dev The proposal must be in the `Ready` or `InProgress` status.
    ///      A `ProposalExecuted` event will be emitted with a non-empty `nextProgressData`
    ///      if the proposal has extra steps (must be executed again) to carry out,
    ///      in which case `nextProgressData` should be passed into the next `execute()` call.
    ///      The `ProposalExecutionEngine` enforces that only one `InProgress` proposal
    ///      is active at a time, so that proposal must be completed or cancelled via `cancel()`
    ///      in order to execute a different proposal.
    ///      `extraData` is optional, off-chain data a proposal might need to execute a step.
    /// @param proposalId The ID of the proposal to execute.
    /// @param proposal The details of the proposal.
    /// @param preciousTokens The tokens that the party considers precious.
    /// @param preciousTokenIds The token IDs associated with each precious token.
    /// @param progressData The data returned from the last `execute()` call, if any.
    /// @param extraData Off-chain data a proposal might need to execute a step.
    function execute(
        uint256 proposalId,
        Proposal memory proposal,
        IERC721[] memory preciousTokens,
        uint256[] memory preciousTokenIds,
        bytes calldata progressData,
        bytes calldata extraData
    )
        external
        payable
        onlyActiveMember
        onlyWhenNotGloballyDisabled
        onlyDelegateCall
    {
        // Get information about the proposal.
        ProposalState storage proposalState = _proposalStateByProposalId[proposalId];
        // Proposal details must remain the same from `propose()`.
        _validateProposalHash(proposal, proposalState.hash);
        ProposalStateValues memory values = proposalState.values;
        ProposalStatus status = _getProposalStatus(values);
        // The proposal must be executable or have already been executed but still
        // has more steps to go.
        if (status != ProposalStatus.Ready && status != ProposalStatus.InProgress) {
            revert BadProposalStatusError(status);
        }
        if (status == ProposalStatus.Ready) {
            // If the proposal has not been executed yet, make sure it hasn't
            // expired. Note that proposals that have been executed
            // (but still have more steps) ignore `maxExecutableTime`.
            if (proposal.maxExecutableTime < block.timestamp) {
                revert ExecutionTimeExceededError(
                    proposal.maxExecutableTime,
                    uint40(block.timestamp)
                );
            }
            proposalState.values.executedTime = uint40(block.timestamp);
        }
        // Check that the precious list is valid.
        if (!_isPreciousListCorrect(preciousTokens, preciousTokenIds)) {
            revert BadPreciousListError();
        }
        // Preemptively set the proposal to completed to avoid it being executed
        // again in a deeper call.
        proposalState.values.completedTime = uint40(block.timestamp);
        // Execute the proposal.
        bool completed = _executeProposal(
            proposalId,
            proposal,
            preciousTokens,
            preciousTokenIds,
            _getProposalFlags(values),
            progressData,
            extraData
        );
        if (!completed) {
            // Proposal did not complete.
            proposalState.values.completedTime = 0;
        }
    }

    /// @notice Cancel a (probably stuck) InProgress proposal.
    /// @dev `proposal.cancelDelay` seconds must have passed since it was first
    ///      executed for this to be valid. The currently active proposal will
    ///      simply be yeeted out of existence so another proposal can execute.
    ///      This is intended to be a last resort and can leave the party in a
    ///      broken state. Whenever possible, active proposals should be
    ///      allowed to complete their lifecycle.
    /// @param proposalId The ID of the proposal to cancel.
    /// @param proposal The details of the proposal to cancel.
    function cancel(uint256 proposalId, Proposal calldata proposal)
        external
        onlyActiveMember
        onlyDelegateCall
    {
        // Get information about the proposal.
        ProposalState storage proposalState = _proposalStateByProposalId[proposalId];
        // Proposal details must remain the same from `propose()`.
        _validateProposalHash(proposal, proposalState.hash);
        ProposalStateValues memory values = proposalState.values;
        {
            // Must be `InProgress`.
            ProposalStatus status = _getProposalStatus(values);
            if (status != ProposalStatus.InProgress) {
                revert BadProposalStatusError(status);
            }
        }
        {
            // Limit the `cancelDelay` to the global max and min cancel delay
            // to mitigate parties accidentally getting stuck forever by setting an
            // unrealistic `cancelDelay` or being reckless with too low a
            // cancel delay.
            uint256 cancelDelay = proposal.cancelDelay;
            uint256 globalMaxCancelDelay =
                _GLOBALS.getUint256(LibGlobals.GLOBAL_PROPOSAL_MAX_CANCEL_DURATION);
            uint256 globalMinCancelDelay =
                _GLOBALS.getUint256(LibGlobals.GLOBAL_PROPOSAL_MIN_CANCEL_DURATION);
            if (globalMaxCancelDelay != 0) { // Only if we have one set.
                if (cancelDelay > globalMaxCancelDelay) {
                    cancelDelay = globalMaxCancelDelay;
                }
            }
            if (globalMinCancelDelay != 0) { // Only if we have one set.
                if (cancelDelay < globalMinCancelDelay) {
                    cancelDelay = globalMinCancelDelay;
                }
            }
            uint256 cancelTime = values.executedTime + cancelDelay;
            // Must not be too early.
            if (block.timestamp < cancelTime) {
                revert ProposalCannotBeCancelledYetError(
                    uint40(block.timestamp),
                    uint40(cancelTime)
                );
            }
        }
        // Mark the proposal as cancelled by setting the completed time to the current
        // time with the high bit set.
        proposalState.values.completedTime = uint40(block.timestamp | UINT40_HIGH_BIT);
        {
            // Delegatecall into the proposal engine impl to perform the cancel.
            (bool success, bytes memory resultData) =
            (address(_getProposalExecutionEngine())).delegatecall(abi.encodeCall(
                IProposalExecutionEngine.cancelProposal,
                (proposalId)
            ));
            if (!success) {
                resultData.rawRevert();
            }
        }
        emit ProposalCancelled(proposalId);
    }

    /// @notice As the DAO, execute an arbitrary function call from this contract.
    /// @dev Emergency actions must not be revoked for this to work.
    /// @param targetAddress The contract to call.
    /// @param targetCallData The data to pass to the contract.
    /// @param amountEth The amount of ETH to send to the contract.
    function emergencyExecute(
        address targetAddress,
        bytes calldata targetCallData,
        uint256 amountEth
    )
        external
        payable
        onlyPartyDao
        onlyWhenEmergencyExecuteAllowed
        onlyDelegateCall
    {
        (bool success, bytes memory res) = targetAddress.call{value: amountEth}(targetCallData);
        if (!success) {
            res.rawRevert();
        }
        emit EmergencyExecute(targetAddress, targetCallData, amountEth);
    }

    /// @notice Revoke the DAO's ability to call emergencyExecute().
    /// @dev Either the DAO or the party host can call this.
    function disableEmergencyExecute() external onlyPartyDaoOrHost onlyDelegateCall {
        emergencyExecuteDisabled = true;
        emit EmergencyExecuteDisabled();
    }

    function _executeProposal(
        uint256 proposalId,
        Proposal memory proposal,
        IERC721[] memory preciousTokens,
        uint256[] memory preciousTokenIds,
        uint256 flags,
        bytes memory progressData,
        bytes memory extraData
    )
        private
        returns (bool completed)
    {
        // Setup the arguments for the proposal execution engine.
        IProposalExecutionEngine.ExecuteProposalParams memory executeParams =
            IProposalExecutionEngine.ExecuteProposalParams({
                proposalId: proposalId,
                proposalData: proposal.proposalData,
                progressData: progressData,
                extraData: extraData,
                preciousTokens: preciousTokens,
                preciousTokenIds: preciousTokenIds,
                flags: flags
            });
        // Get the progress data returned after the proposal is executed.
        bytes memory nextProgressData;
        {
            // Execute the proposal.
            (bool success, bytes memory resultData) =
                address(_getProposalExecutionEngine()).delegatecall(abi.encodeCall(
                    IProposalExecutionEngine.executeProposal,
                    (executeParams)
                ));
            if (!success) {
                resultData.rawRevert();
            }
            nextProgressData = abi.decode(resultData, (bytes));
        }
        emit ProposalExecuted(proposalId, msg.sender, nextProgressData);
        // If the returned progress data is empty, then the proposal completed
        // and it should not be executed again.
        return nextProgressData.length == 0;
    }

    // Get the most recent voting power snapshot <= timestamp using `hintindex` as a "hint".
    function _getVotingPowerSnapshotAt(address voter, uint40 timestamp, uint256 hintIndex)
        internal
        view
        returns (VotingPowerSnapshot memory snap)
    {
        VotingPowerSnapshot[] storage snaps = _votingPowerSnapshotsByVoter[voter];
        uint256 snapsLength = snaps.length;
        if (snapsLength != 0) {
            if (
                // Hint is within bounds.
                hintIndex < snapsLength &&
                // Snapshot is not too recent.
                snaps[hintIndex].timestamp <= timestamp &&
                // Snapshot is not too old.
                (hintIndex == snapsLength - 1 || snaps[hintIndex+1].timestamp > timestamp)
            ) {
                return snaps[hintIndex];
            }

            // Hint was wrong, fallback to binary search to find snapshot.
            hintIndex = findVotingPowerSnapshotIndex(voter, timestamp);
            // Check that snapshot was found.
            if (hintIndex != type(uint256).max) {
                return snaps[hintIndex];
            }
        }

        // No snapshot found.
        return snap;
    }

    // Transfers some voting power of `from` to `to`. The total voting power of
    // their respective delegates will be updated as well.
    function _transferVotingPower(address from, address to, uint256 power)
        internal
    {
        int192 powerI192 = power.safeCastUint256ToInt192();
        _adjustVotingPower(from, -powerI192, address(0));
        _adjustVotingPower(to, powerI192, address(0));
    }

    // Increase `voter`'s intrinsic voting power and update their delegate if delegate is nonzero.
    function _adjustVotingPower(address voter, int192 votingPower, address delegate)
        internal
    {
        VotingPowerSnapshot memory oldSnap =
            _getLastVotingPowerSnapshotForVoter(voter);
        address oldDelegate = delegationsByVoter[voter];
        // If `oldDelegate` is zero and `voter` never delegated, then have
        // `voter` delegate to themself.
        oldDelegate = oldDelegate == address(0) ? voter : oldDelegate;
        // If the new `delegate` is zero, use the current (old) delegate.
        delegate = delegate == address(0) ? oldDelegate : delegate;

        VotingPowerSnapshot memory newSnap = VotingPowerSnapshot({
            timestamp: uint40(block.timestamp),
            delegatedVotingPower: oldSnap.delegatedVotingPower,
            intrinsicVotingPower: (
                    oldSnap.intrinsicVotingPower.safeCastUint96ToInt192() + votingPower
                ).safeCastInt192ToUint96(),
            isDelegated: delegate != voter
        });
        _insertVotingPowerSnapshot(voter, newSnap);
        delegationsByVoter[voter] = delegate;
        // Handle rebalancing delegates.
        _rebalanceDelegates(voter, oldDelegate, delegate, oldSnap, newSnap);
    }

    function _getTotalVotingPower() internal view returns (uint256) {
        return _governanceValues.totalVotingPower;
    }

    // Update the delegated voting power of the old and new delegates delegated to
    // by `voter` based on the snapshot change.
    function _rebalanceDelegates(
        address voter,
        address oldDelegate,
        address newDelegate,
        VotingPowerSnapshot memory oldSnap,
        VotingPowerSnapshot memory newSnap
    )
        private
    {
        if (newDelegate == address(0) || oldDelegate == address(0)) {
            revert InvalidDelegateError();
        }
        if (oldDelegate != voter && oldDelegate != newDelegate) {
            // Remove past voting power from old delegate.
            VotingPowerSnapshot memory oldDelegateSnap =
                _getLastVotingPowerSnapshotForVoter(oldDelegate);
            VotingPowerSnapshot memory updatedOldDelegateSnap =
                VotingPowerSnapshot({
                    timestamp: uint40(block.timestamp),
                    delegatedVotingPower:
                        oldDelegateSnap.delegatedVotingPower -
                            oldSnap.intrinsicVotingPower,
                    intrinsicVotingPower: oldDelegateSnap.intrinsicVotingPower,
                    isDelegated: oldDelegateSnap.isDelegated
                });
            _insertVotingPowerSnapshot(oldDelegate, updatedOldDelegateSnap);
        }
        if (newDelegate != voter) { // Not delegating to self.
            // Add new voting power to new delegate.
            VotingPowerSnapshot memory newDelegateSnap =
                _getLastVotingPowerSnapshotForVoter(newDelegate);
            uint96 newDelegateDelegatedVotingPower =
                newDelegateSnap.delegatedVotingPower + newSnap.intrinsicVotingPower;
            if (newDelegate == oldDelegate) {
                // If the old and new delegate are the same, subtract the old
                // intrinsic voting power of the voter, or else we will double
                // count a portion of it.
                newDelegateDelegatedVotingPower -= oldSnap.intrinsicVotingPower;
            }
            VotingPowerSnapshot memory updatedNewDelegateSnap =
                VotingPowerSnapshot({
                    timestamp: uint40(block.timestamp),
                    delegatedVotingPower: newDelegateDelegatedVotingPower,
                    intrinsicVotingPower: newDelegateSnap.intrinsicVotingPower,
                    isDelegated: newDelegateSnap.isDelegated
                });
            _insertVotingPowerSnapshot(newDelegate, updatedNewDelegateSnap);
        }
    }

    // Append a new voting power snapshot, overwriting the last one if possible.
    function _insertVotingPowerSnapshot(address voter, VotingPowerSnapshot memory snap)
        private
    {
        VotingPowerSnapshot[] storage voterSnaps = _votingPowerSnapshotsByVoter[voter];
        uint256 n = voterSnaps.length;
        // If same timestamp as last entry, overwrite the last snapshot, otherwise append.
        if (n != 0) {
            VotingPowerSnapshot memory lastSnap = voterSnaps[n - 1];
            if (lastSnap.timestamp == snap.timestamp) {
                voterSnaps[n - 1] = snap;
                return;
            }
        }
        voterSnaps.push(snap);
    }

    function _getLastVotingPowerSnapshotForVoter(address voter)
        private
        view
        returns (VotingPowerSnapshot memory snap)
    {
        VotingPowerSnapshot[] storage voterSnaps = _votingPowerSnapshotsByVoter[voter];
        uint256 n = voterSnaps.length;
        if (n != 0) {
            snap = voterSnaps[n - 1];
        }
    }

    function _getProposalFlags(ProposalStateValues memory pv)
        private
        view
        returns (uint256)
    {
        if (_isUnanimousVotes(pv.votes, _governanceValues.totalVotingPower)) {
            return LibProposal.PROPOSAL_FLAG_UNANIMOUS;
        }
        return 0;
    }

    function _getProposalStatus(ProposalStateValues memory pv)
        private
        view
        returns (ProposalStatus status)
    {
        // Never proposed.
        if (pv.proposedTime == 0) {
            return ProposalStatus.Invalid;
        }
        // Executed at least once.
        if (pv.executedTime != 0) {
            if (pv.completedTime == 0) {
                return ProposalStatus.InProgress;
            }
            // completedTime high bit will be set if cancelled.
            if (pv.completedTime & UINT40_HIGH_BIT == UINT40_HIGH_BIT) {
                return ProposalStatus.Cancelled;
            }
            return ProposalStatus.Complete;
        }
        // Vetoed.
        if (pv.votes == type(uint96).max) {
            return ProposalStatus.Defeated;
        }
        uint40 t = uint40(block.timestamp);
        GovernanceValues memory gv = _governanceValues;
        if (pv.passedTime != 0) {
            // Ready.
            if (pv.passedTime + gv.executionDelay <= t) {
                return ProposalStatus.Ready;
            }
            // If unanimous, we skip the execution delay.
            if (_isUnanimousVotes(pv.votes, gv.totalVotingPower)) {
                return ProposalStatus.Ready;
            }
            // Passed.
            return ProposalStatus.Passed;
        }
        // Voting window expired.
        if (pv.proposedTime + gv.voteDuration <= t) {
            return ProposalStatus.Defeated;
        }
        return ProposalStatus.Voting;
    }

    function _isUnanimousVotes(uint96 totalVotes, uint96 totalVotingPower)
        private
        pure
        returns (bool)
    {
        uint256 acceptanceRatio = (totalVotes * 1e4) / totalVotingPower;
        // If >= 99.99% acceptance, consider it unanimous.
        // The minting formula for voting power is a bit lossy, so we check
        // for slightly less than 100%.
        return acceptanceRatio >= 0.9999e4;
    }

    function _areVotesPassing(
        uint96 voteCount,
        uint96 totalVotingPower,
        uint16 passThresholdBps
    )
        private
        pure
        returns (bool)
    {
          return uint256(voteCount) * 1e4
            / uint256(totalVotingPower) >= uint256(passThresholdBps);
    }

    function _setPreciousList(
        IERC721[] memory preciousTokens,
        uint256[] memory preciousTokenIds
    )
        private
    {
        if (preciousTokens.length != preciousTokenIds.length) {
            revert MismatchedPreciousListLengths();
        }
        preciousListHash = _hashPreciousList(preciousTokens, preciousTokenIds);
    }

    function _isPreciousListCorrect(
        IERC721[] memory preciousTokens,
        uint256[] memory preciousTokenIds
    )
        private
        view
        returns (bool)
    {
        return preciousListHash == _hashPreciousList(preciousTokens, preciousTokenIds);
    }

    function _hashPreciousList(
        IERC721[] memory preciousTokens,
        uint256[] memory preciousTokenIds
    )
        internal
        pure
        returns (bytes32 h)
    {
        assembly {
            mstore(0x00, keccak256(
                add(preciousTokens, 0x20),
                mul(mload(preciousTokens), 0x20)
            ))
            mstore(0x20, keccak256(
                add(preciousTokenIds, 0x20),
                mul(mload(preciousTokenIds), 0x20)
            ))
            h := keccak256(0x00, 0x40)
        }
    }

    // Assert that the hash of a proposal matches expectedHash.
    function _validateProposalHash(Proposal memory proposal, bytes32 expectedHash)
        private
        pure
    {
        bytes32 actualHash = getProposalHash(proposal);
        if (expectedHash != actualHash) {
            revert BadProposalHashError(actualHash, expectedHash);
        }
    }

}

File 8 of 30 : PartyGovernanceNFT.sol
// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.17;

import "../utils/ReadOnlyDelegateCall.sol";
import "../utils/LibSafeCast.sol";
import "openzeppelin/contracts/interfaces/IERC2981.sol";
import "../globals/IGlobals.sol";
import "../tokens/IERC721.sol";
import "../vendor/solmate/ERC721.sol";
import "./PartyGovernance.sol";
import "../renderers/RendererStorage.sol";

/// @notice ERC721 functionality built on top of `PartyGovernance`.
contract PartyGovernanceNFT is
    PartyGovernance,
    ERC721,
    IERC2981
{
    using LibSafeCast for uint256;
    using LibSafeCast for uint96;

    error OnlyMintAuthorityError(address actual, address expected);

    // The `Globals` contract storing global configuration values. This contract
    // is immutable and it’s address will never change.
    IGlobals private immutable _GLOBALS;

    /// @notice Who can call `mint()`. Usually this will be the crowdfund contract that
    /// created the party.
    address public mintAuthority;
    /// @notice The number of tokens that have been minted.
    uint96 public tokenCount;
    /// @notice The total minted voting power.
    ///         Capped to `_governanceValues.totalVotingPower`
    uint96 public mintedVotingPower;
    /// @notice The voting power of `tokenId`.
    mapping (uint256 => uint256) public votingPowerByTokenId;

    modifier onlyMinter() {
        address minter = mintAuthority;
        if (msg.sender != minter) {
            revert OnlyMintAuthorityError(msg.sender, minter);
        }
        _;
    }

    // Set the `Globals` contract. The name of symbol of ERC721 does not matter;
    // it will be set in `_initialize()`.
    constructor(IGlobals globals) PartyGovernance(globals) ERC721('', '') {
        _GLOBALS = globals;
    }

    // Initialize storage for proxy contracts.
    function _initialize(
        string memory name_,
        string memory symbol_,
        uint256 customizationPresetId,
        PartyGovernance.GovernanceOpts memory governanceOpts,
        IERC721[] memory preciousTokens,
        uint256[] memory preciousTokenIds,
        address mintAuthority_
    )
        internal
    {
        PartyGovernance._initialize(governanceOpts, preciousTokens, preciousTokenIds);
        name = name_;
        symbol = symbol_;
        mintAuthority = mintAuthority_;
        if (customizationPresetId != 0) {
            RendererStorage(_GLOBALS.getAddress(LibGlobals.GLOBAL_RENDERER_STORAGE))
                .useCustomizationPreset(customizationPresetId);
        }
    }

    /// @inheritdoc ERC721
    function ownerOf(uint256 tokenId)
        public
        view
        override(ERC721, ITokenDistributorParty)
        returns (address owner)
    {
        return ERC721.ownerOf(tokenId);
    }

    /// @inheritdoc EIP165
    function supportsInterface(bytes4 interfaceId)
        public
        pure
        override(PartyGovernance, ERC721, IERC165)
        returns (bool)
    {
        return PartyGovernance.supportsInterface(interfaceId) ||
            ERC721.supportsInterface(interfaceId) ||
            interfaceId == type(IERC2981).interfaceId;
    }

    /// @inheritdoc ERC721
    function tokenURI(uint256) public override view returns (string memory) {
        _delegateToRenderer();
        return ""; // Just to make the compiler happy.
    }

    /// @notice Returns a URI for the storefront-level metadata for your contract.
    function contractURI() external view returns (string memory) {
        _delegateToRenderer();
        return ""; // Just to make the compiler happy.
    }

    /// @notice Called with the sale price to determine how much royalty
    //          is owed and to whom.
    function royaltyInfo(uint256, uint256)
        external
        view
        returns (address, uint256)
    {
        _delegateToRenderer();
        return (address(0), 0); // Just to make the compiler happy.
    }

    /// @inheritdoc ITokenDistributorParty
    function getDistributionShareOf(uint256 tokenId) external view returns (uint256) {
        return votingPowerByTokenId[tokenId] * 1e18 / _getTotalVotingPower();
    }

    /// @notice Mint a governance NFT for `owner` with `votingPower` and
    /// immediately delegate voting power to `delegate.`
    /// @param owner The owner of the NFT.
    /// @param votingPower The voting power of the NFT.
    /// @param delegate The address to delegate voting power to.
    function mint(
        address owner,
        uint256 votingPower,
        address delegate
    )
        external
        onlyMinter
        onlyDelegateCall
        returns (uint256 tokenId)
    {
        (uint96 tokenCount_, uint96 mintedVotingPower_) = (tokenCount, mintedVotingPower);
        uint96 totalVotingPower = _governanceValues.totalVotingPower;
        // Cap voting power to remaining unminted voting power supply.
        uint96 votingPower_ = votingPower.safeCastUint256ToUint96();
        if (totalVotingPower - mintedVotingPower_ < votingPower_) {
            votingPower_ = totalVotingPower - mintedVotingPower_;
        }
        mintedVotingPower_ += votingPower_;
        // Update state.
        tokenId = tokenCount = tokenCount_ + 1;
        mintedVotingPower = mintedVotingPower_;
        votingPowerByTokenId[tokenId] = votingPower_;

        // Use delegate from party over the one set during crowdfund.
        address delegate_ = delegationsByVoter[owner];
        if (delegate_ != address(0)) {
            delegate = delegate_;
        }

        _adjustVotingPower(owner, votingPower_.safeCastUint96ToInt192(), delegate);
        _safeMint(owner, tokenId);
    }

    /// @inheritdoc ERC721
    function transferFrom(address owner, address to, uint256 tokenId)
        public
        override
        onlyDelegateCall
    {
        // Transfer voting along with token.
        _transferVotingPower(owner, to, votingPowerByTokenId[tokenId]);
        super.transferFrom(owner, to, tokenId);
    }

    /// @inheritdoc ERC721
    function safeTransferFrom(address owner, address to, uint256 tokenId)
        public
        override
        onlyDelegateCall
    {
        // super.safeTransferFrom() will call transferFrom() first which will
        // transfer voting power.
        super.safeTransferFrom(owner, to, tokenId);
    }

    /// @inheritdoc ERC721
    function safeTransferFrom(address owner, address to, uint256 tokenId, bytes calldata data)
        public
        override
        onlyDelegateCall
    {
        // super.safeTransferFrom() will call transferFrom() first which will
        // transfer voting power.
        super.safeTransferFrom(owner, to, tokenId, data);
    }

    /// @notice Relinquish the ability to call `mint()` by an authority.
    function abdicate() external onlyMinter onlyDelegateCall {
        delete mintAuthority;
    }

    function _delegateToRenderer() private view {
        _readOnlyDelegateCall(
            // Instance of IERC721Renderer.
            _GLOBALS.getAddress(LibGlobals.GLOBAL_GOVERNANCE_NFT_RENDER_IMPL),
            msg.data
        );
        assert(false); // Will not be reached.
    }
}

File 9 of 30 : IProposalExecutionEngine.sol
// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.17;

import "../tokens/IERC721.sol";

// Upgradeable proposals logic contract interface.
interface IProposalExecutionEngine {
    struct ExecuteProposalParams {
        uint256 proposalId;
        bytes proposalData;
        bytes progressData;
        bytes extraData;
        uint256 flags;
        IERC721[] preciousTokens;
        uint256[] preciousTokenIds;
    }

    function initialize(address oldImpl, bytes memory initData) external;

    /// @notice Execute a proposal.
    /// @dev Must be delegatecalled into by PartyGovernance.
    ///      If the proposal is incomplete, continues its next step (if possible).
    ///      If another proposal is incomplete, this will fail. Only one
    ///      incomplete proposal is allowed at a time.
    /// @param params The data needed to execute the proposal.
    /// @return nextProgressData Bytes to be passed into the next `execute()` call,
    ///         if the proposal execution is incomplete. Otherwise, empty bytes
    ///         to indicate the proposal is complete.
    function executeProposal(ExecuteProposalParams memory params)
        external returns (bytes memory nextProgressData);

    /// @notice Forcibly cancel an incomplete proposal.
    /// @param proposalId The ID of the proposal to cancel.
    /// @dev This is intended to be a last resort as it can leave a party in a
    ///      broken step. Whenever possible, proposals should be allowed to
    ///      complete their entire lifecycle.
    function cancelProposal(uint256 proposalId) external;
}

File 10 of 30 : LibProposal.sol
// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.17;

import "../tokens/IERC721.sol";

library LibProposal {
    uint256 internal constant PROPOSAL_FLAG_UNANIMOUS = 0x1;

    function isTokenPrecious(IERC721 token, IERC721[] memory preciousTokens)
        internal
        pure
        returns (bool)
    {
        for (uint256 i; i < preciousTokens.length; ++i) {
            if (token == preciousTokens[i]) {
                return true;
            }
        }
        return false;
    }

    function isTokenIdPrecious(
        IERC721 token,
        uint256 tokenId,
        IERC721[] memory preciousTokens,
        uint256[] memory preciousTokenIds
    )
        internal
        pure
        returns (bool)
    {
        for (uint256 i; i < preciousTokens.length; ++i) {
            if (token == preciousTokens[i] && tokenId == preciousTokenIds[i]) {
                return true;
            }
        }
        return false;
    }
}

File 11 of 30 : ProposalStorage.sol
// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.17;

import "./IProposalExecutionEngine.sol";
import "../utils/LibRawResult.sol";

// The storage bucket shared by `PartyGovernance` and the `ProposalExecutionEngine`.
// Read this for more context on the pattern motivating this:
// https://github.com/dragonfly-xyz/useful-solidity-patterns/tree/main/patterns/explicit-storage-buckets
abstract contract ProposalStorage {
    using LibRawResult for bytes;

    struct SharedProposalStorage {
        IProposalExecutionEngine engineImpl;
    }

    uint256 internal constant PROPOSAL_FLAG_UNANIMOUS = 0x1;
    uint256 private constant SHARED_STORAGE_SLOT = uint256(keccak256("ProposalStorage.SharedProposalStorage"));

    function _getProposalExecutionEngine()
        internal
        view
        returns (IProposalExecutionEngine impl)
    {
        return _getSharedProposalStorage().engineImpl;
    }

    function _setProposalExecutionEngine(IProposalExecutionEngine impl) internal {
        _getSharedProposalStorage().engineImpl = impl;
    }

    function _initProposalImpl(IProposalExecutionEngine impl, bytes memory initData)
        internal
    {
        SharedProposalStorage storage stor = _getSharedProposalStorage();
        IProposalExecutionEngine oldImpl = stor.engineImpl;
        stor.engineImpl = impl;
        (bool s, bytes memory r) = address(impl).delegatecall(
            abi.encodeCall(
                IProposalExecutionEngine.initialize,
                (address(oldImpl), initData)
            )
        );
        if (!s) {
            r.rawRevert();
        }
    }

    function _getSharedProposalStorage()
        private
        pure
        returns (SharedProposalStorage storage stor)
    {
        uint256 s = SHARED_STORAGE_SLOT;
        assembly { stor.slot := s }
    }

}

File 12 of 30 : RendererStorage.sol
// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.17;

import "solmate/utils/SSTORE2.sol";
import "../utils/Multicall.sol";

contract RendererStorage is Multicall {
    error AlreadySetError();
    error NotOwnerError(address caller, address owner);

    event OwnershipTransferred(address previousOwner, address newOwner);

    uint256 constant CROWDFUND_CARD_DATA = 0;
    uint256 constant PARTY_CARD_DATA = 1;

    /// @notice Address allowed to store new data.
    address public owner;

    /// @notice Customization presets by ID, used for rendering cards. Begins at
    ///         1, 0 is reserved to indicate in `getPresetFor()` that a
    ///         party instance use the preset set by the crowdfund instance that
    ///         created it.
    mapping(uint256 => bytes) public customizationPresets;
    /// @notice Customization preset used by a crowdfund or party instance.
    mapping(address => uint256) public getPresetFor;
    /// @notice Addresses where URI data chunks are stored.
    mapping(uint256 => address) public files;

    modifier onlyOwner() {
        address owner_ = owner;
        if (msg.sender != owner_) {
            revert NotOwnerError(msg.sender, owner_);
        }

        _;
    }

    constructor(address _owner) {
        // Set the address allowed to write new data.
        owner = _owner;

        // Write URI data used by V1 of the renderers:

        files[CROWDFUND_CARD_DATA] = SSTORE2.write(bytes(
            '<path class="o" d="M118.4 419.5h5.82v1.73h-4.02v1.87h3.74v1.73h-3.74v1.94h4.11v1.73h-5.91v-9Zm9.93 1.76h-2.6v-1.76h7.06v1.76h-2.61v7.24h-1.85v-7.24Zm6.06-1.76h1.84v3.55h3.93v-3.55H142v9h-1.84v-3.67h-3.93v3.67h-1.84v-9Z"/><path class="o" d="M145 413a4 4 0 0 1 4 4v14a4 4 0 0 1-4 4H35a4 4 0 0 1-4-4v-14a4 4 0 0 1 4-4h110m0-1H35a5 5 0 0 0-5 5v14a5 5 0 0 0 5 5h110a5 5 0 0 0 5-5v-14a5 5 0 0 0-5-5Z"/><path d="M239.24 399.83h3.04c1.7 0 2.82 1 2.82 2.55 0 2.1-1.27 3.32-3.57 3.32h-1.97l-.71 3.3h-1.56l1.96-9.17Zm2.34 4.38c1.23 0 1.88-.58 1.88-1.68 0-.73-.49-1.2-1.48-1.2h-1.51l-.6 2.88h1.7Zm3.57 1.86c0-2.27 1.44-3.83 3.57-3.83 1.82 0 3.06 1.25 3.06 3.09 0 2.28-1.43 3.83-3.57 3.83-1.82 0-3.06-1.25-3.06-3.09Zm3.13 1.74c1.19 0 1.93-1.02 1.93-2.52 0-1.06-.62-1.69-1.56-1.69-1.19 0-1.93 1.02-1.93 2.52 0 1.06.62 1.69 1.56 1.69Zm4.74-5.41h1.49l.28 4.73 2.25-4.73h1.64l.23 4.77 2.25-4.77h1.56l-3.3 6.61h-1.62l-.25-5.04-2.42 5.04h-1.63l-.48-6.61Zm9.54 3.66c0-2.27 1.45-3.81 3.6-3.81 2 0 3.05 1.58 2.33 3.92h-4.46c0 1.1.81 1.68 2.05 1.68.8 0 1.45-.2 2.1-.59l-.31 1.46a4.2 4.2 0 0 1-2.04.44c-2.06 0-3.26-1.19-3.26-3.11Zm4.7-1.07c.12-.86-.31-1.46-1.22-1.46s-1.57.61-1.82 1.46h3.05Zm3.46-2.59h1.55l-.28 1.28c.81-1.7 2.56-1.36 2.77-1.29l-.35 1.46c-.18-.06-2.3-.63-2.82 1.68l-.74 3.48h-1.55l1.42-6.61Zm3.91 3.66c0-2.27 1.45-3.81 3.6-3.81 2 0 3.05 1.58 2.33 3.92h-4.46c0 1.1.81 1.68 2.05 1.68.8 0 1.45-.2 2.1-.59l-.31 1.46a4.2 4.2 0 0 1-2.04.44c-2.06 0-3.26-1.19-3.26-3.11Zm4.7-1.07c.12-.86-.31-1.46-1.22-1.46s-1.57.61-1.82 1.46h3.05Zm2.25 1.36c0-2.44 1.36-4.1 3.26-4.1 1 0 1.76.53 2.05 1.31l.79-3.72h1.55l-1.96 9.17h-1.55l.2-.92a2.15 2.15 0 0 1-1.92 1.08c-1.49 0-2.43-1.18-2.43-2.82Zm3 1.51c.88 0 1.51-.58 1.73-1.56l.17-.81c.24-1.1-.31-1.93-1.36-1.93-1.19 0-1.94 1.08-1.94 2.59 0 1.06.55 1.71 1.4 1.71Zm9.6-.01-.25 1.16h-1.55l1.96-9.17h1.55l-.73 3.47a2.35 2.35 0 0 1 1.99-1.05c1.49 0 2.35 1.16 2.35 2.76 0 2.52-1.36 4.16-3.21 4.16-.98 0-1.81-.53-2.1-1.32Zm1.83.01c1.16 0 1.87-1.06 1.87-2.61 0-1.04-.5-1.69-1.39-1.69s-1.52.56-1.73 1.55l-.17.79c-.24 1.14.34 1.97 1.42 1.97Zm5.68 1.16-1.04-6.62h1.52l.66 4.75 2.66-4.75h1.69l-5.31 9.13h-1.73l1.55-2.51Zm23.48-6.8a42.14 42.14 0 0 0-.75 6.01 43.12 43.12 0 0 0 5.58 2.35 42.54 42.54 0 0 0 5.58-2.35 45.32 45.32 0 0 0-.75-6.01c-.91-.79-2.6-2.21-4.83-3.66a42.5 42.5 0 0 0-4.83 3.66Zm13.07-7.95s.82-.29 1.76-.45a14.9 14.9 0 0 0-9.53-3.81c.66.71 1.28 1.67 1.84 2.75 1.84.22 4.07.7 5.92 1.51Zm-2.71 18.36c-2.06-.4-4.05-.97-5.53-1.51a38.65 38.65 0 0 1-5.53 1.51c.12 1.5.35 3.04.76 4.58 0 0 1.54 1.82 4.78 2.8 3.23-.98 4.78-2.8 4.78-2.8.4-1.53.64-3.08.76-4.58Zm-13.77-18.37a22.3 22.3 0 0 1 5.93-1.51 12.4 12.4 0 0 1 1.84-2.75 14.97 14.97 0 0 0-9.53 3.81c.95.16 1.76.45 1.76.45Zm-4.72 8.77a25.74 25.74 0 0 0 3.58 2.94 37.48 37.48 0 0 1 4.08-4.04c.27-1.56.77-3.57 1.46-5.55a25.24 25.24 0 0 0-4.34-1.63s-2.35.42-4.81 2.74c-.77 3.29.04 5.54.04 5.54Zm25.92 0s.81-2.25.04-5.54c-2.46-2.31-4.81-2.74-4.81-2.74-1.53.42-2.99.99-4.34 1.63a37.79 37.79 0 0 1 1.46 5.55 37.44 37.44 0 0 1 4.08 4.04 25.86 25.86 0 0 0 3.58-2.94Zm-26.38.2s-.66-.56-1.27-1.3c-.7 3.34-.27 6.93 1.46 10.16.28-.93.8-1.94 1.46-2.97a22.32 22.32 0 0 1-1.66-5.88Zm8.24 14.27a22.07 22.07 0 0 1-4.27-4.38c-1.22.06-2.36 0-3.3-.22a14.91 14.91 0 0 0 8.07 6.34c-.34-.9-.5-1.75-.5-1.75Zm18.6-14.27s.66-.56 1.27-1.3c.7 3.34.27 6.93-1.46 10.16-.28-.93-.8-1.94-1.46-2.97a22.32 22.32 0 0 0 1.66-5.88Zm-8.24 14.27a22.07 22.07 0 0 0 4.27-4.38c1.22.06 2.36 0 3.3-.22a14.91 14.91 0 0 1-8.07 6.34c.34-.9.5-1.75.5-1.75ZM330 391.84l-4.12 2.45 1.26 3.91h5.72l1.26-3.91-4.12-2.45Zm-11.4 19.74 4.18 2.35 2.75-3.05-2.86-4.95-4.02.86-.06 4.79Zm22.79 0-.06-4.79-4.02-.86-2.86 4.95 2.75 3.05 4.18-2.35Z" style="fill:#00c1fa"/><use height="300" transform="matrix(1 0 0 .09 29.85 444)" width="300.15" xlink:href="#a"/><use height="21.15" transform="translate(30 446.92)" width="300" xlink:href="#b"/><g><path d="m191.54 428.67-28.09-24.34A29.98 29.98 0 0 0 143.8 397H30a15 15 0 0 0-15 15v98a15 15 0 0 0 15 15h300a15 15 0 0 0 15-15v-59a15 15 0 0 0-15-15H211.19a30 30 0 0 1-19.65-7.33Z" style="fill:url(#i)"/></g></svg>'
        ));

        files[PARTY_CARD_DATA] = SSTORE2.write(bytes(
            ' d="M30 444.28h4.3c3.05 0 5.17 2.13 5.17 5.36s-2.11 5.35-5.17 5.35H30v-10.72Zm3.95 8.61c2.07 0 3.24-1.2 3.24-3.25s-1.16-3.26-3.24-3.26h-1.77v6.51h1.77Zm7.78-8.61h2.19V455h-2.19v-10.72Zm4.79 10.02v-2.31c1 .74 2.13 1.13 3.25 1.13s1.68-.45 1.68-1.23c0-.69-.39-.95-1.23-1.19l-1.19-.34c-1.78-.48-2.65-1.46-2.65-3.1 0-1.95 1.5-3.18 3.87-3.18 1.05 0 2.09.21 2.91.66V447a5.53 5.53 0 0 0-2.96-.84c-.93 0-1.57.35-1.57 1.06.01.6.39.91 1.16 1.12l1.32.39c1.82.5 2.61 1.42 2.61 3.07 0 2.1-1.53 3.39-3.82 3.39a6.08 6.08 0 0 1-3.38-.9Zm11.93-7.92h-3.1v-2.1h8.41v2.1h-3.11V455h-2.2v-8.62Zm7.56-2.1h4.5c2 0 3.33 1.26 3.33 3.25 0 1.86-1.18 3.1-3.01 3.19l3.53 4.27H71.7l-3.54-4.43v4.43h-2.14v-10.72Zm4.1 4.85c.98 0 1.54-.55 1.54-1.44s-.56-1.43-1.54-1.43h-1.96v2.87h1.96Zm6.04-4.85h2.19V455h-2.19v-10.72Zm5.07 0h4.5c1.99 0 3.21 1.15 3.21 2.79 0 1.06-.5 1.93-1.36 2.32a2.46 2.46 0 0 1 1.78 2.49c0 1.9-1.33 3.11-3.52 3.11h-4.61v-10.72Zm4.17 4.4c.87 0 1.37-.45 1.37-1.26s-.5-1.26-1.37-1.26h-2.06v2.52h2.06Zm.34 4.44c.88 0 1.46-.46 1.46-1.29s-.57-1.3-1.46-1.3h-2.39v2.59h2.39Zm5.63-2.51v-6.33h2.18v6.29c0 1.6.88 2.52 2.3 2.52s2.28-.92 2.28-2.52v-6.29h2.18v6.33c0 2.86-1.72 4.58-4.47 4.58s-4.48-1.72-4.48-4.58Zm14.21-4.23h-3.1v-2.1h8.41v2.1h-3.11V455h-2.2v-8.62Zm7.56-2.1h2.18V455h-2.18v-10.72Zm4.45 5.36c0-3.25 2.21-5.56 5.32-5.56s5.28 2.31 5.28 5.56-2.2 5.55-5.28 5.55-5.32-2.31-5.32-5.55Zm5.32 3.45c1.85 0 3-1.34 3-3.45s-1.15-3.46-3-3.46-3.04 1.34-3.04 3.46 1.16 3.45 3.04 3.45Zm7.54-8.81h2.94l4.03 8.17v-8.17h2.07V455h-2.93l-4.03-8.17V455h-2.09v-10.72Zm11.65 10.02v-2.31c.99.74 2.13 1.13 3.25 1.13s1.68-.45 1.68-1.23c0-.69-.39-.95-1.23-1.19l-1.19-.34c-1.78-.48-2.65-1.46-2.65-3.1 0-1.95 1.5-3.18 3.87-3.18 1.05 0 2.09.21 2.91.66V447a5.53 5.53 0 0 0-2.96-.84c-.92 0-1.57.35-1.57 1.06.01.6.39.91 1.16 1.12l1.32.39c1.82.5 2.61 1.42 2.61 3.07 0 2.1-1.53 3.39-3.82 3.39a6.08 6.08 0 0 1-3.38-.9Zm45.9-10.02h2.38l2.63 8.18 2.72-8.18h2.33L194.39 455h-2.76l-3.64-10.72Zm11.19 5.36c0-3.25 2.21-5.56 5.32-5.56s5.28 2.31 5.28 5.56-2.2 5.55-5.28 5.55-5.32-2.31-5.32-5.55Zm5.32 3.45c1.85 0 3-1.34 3-3.45s-1.15-3.46-3-3.46-3.04 1.34-3.04 3.46 1.16 3.45 3.04 3.45Zm9.41-6.71h-3.1v-2.1h8.41v2.1h-3.11V455h-2.2v-8.62Zm7.56-2.1h6.93v2.06h-4.79v2.23h4.45v2.06h-4.45v2.31h4.89V455h-7.03v-10.72Zm14.17 0h4.27c2.25 0 3.66 1.33 3.66 3.52s-1.4 3.53-3.66 3.53h-2.11V455h-2.16v-10.72Zm4.08 4.99c1.06 0 1.61-.53 1.61-1.47s-.55-1.46-1.61-1.46h-1.92v2.93h1.92Zm5.49.38c0-3.25 2.21-5.56 5.32-5.56s5.28 2.31 5.28 5.56-2.2 5.55-5.28 5.55-5.32-2.31-5.32-5.55Zm5.32 3.45c1.85 0 3-1.34 3-3.45s-1.15-3.46-3-3.46-3.04 1.34-3.04 3.46 1.16 3.45 3.04 3.45Zm6.54-8.81h2.34l1.69 7.84 1.86-7.84h2.41l1.82 7.84 1.75-7.84h2.27l-2.66 10.72H266l-1.88-8.15-1.85 8.15h-2.55l-2.66-10.72Zm16.11 0h6.93v2.06h-4.79v2.23h4.45v2.06h-4.45v2.31h4.89v2.06h-7.03v-10.72Zm9.69 0h4.5c2 0 3.33 1.26 3.33 3.25 0 1.86-1.18 3.1-3.01 3.19l3.53 4.27h-2.66l-3.54-4.43V455h-2.14v-10.72Zm4.1 4.85c.98 0 1.54-.55 1.54-1.44s-.56-1.43-1.54-1.43h-1.96v2.87h1.96ZM30 259.28h4.27c2.25 0 3.66 1.33 3.66 3.52s-1.4 3.53-3.66 3.53h-2.12V270h-2.16v-10.72Zm4.08 4.99c1.06 0 1.61-.53 1.61-1.47s-.55-1.46-1.61-1.46h-1.92v2.93h1.92Zm6.1-4.99h4.5c2 0 3.33 1.26 3.33 3.25 0 1.86-1.18 3.1-3.01 3.19l3.53 4.27h-2.66l-3.54-4.43v4.43h-2.14v-10.72Zm4.1 4.85c.98 0 1.54-.55 1.54-1.44s-.56-1.43-1.54-1.43h-1.96v2.87h1.96Zm5.43.52c0-3.25 2.21-5.56 5.32-5.56s5.28 2.31 5.28 5.56-2.2 5.55-5.28 5.55-5.32-2.31-5.32-5.55Zm5.32 3.45c1.85 0 3-1.34 3-3.45s-1.15-3.46-3-3.46-3.04 1.34-3.04 3.46 1.16 3.45 3.04 3.45Zm7.54-8.81h4.27c2.25 0 3.66 1.33 3.66 3.52s-1.4 3.53-3.66 3.53h-2.11v3.67h-2.16v-10.72Zm4.08 4.99c1.06 0 1.61-.53 1.61-1.47s-.55-1.46-1.61-1.46h-1.92v2.93h1.92Zm5.49.38c0-3.25 2.21-5.56 5.32-5.56s5.28 2.31 5.28 5.56-2.2 5.55-5.28 5.55-5.32-2.31-5.32-5.55Zm5.32 3.45c1.85 0 3-1.34 3-3.45s-1.15-3.46-3-3.46-3.04 1.34-3.04 3.46 1.16 3.45 3.04 3.45Zm7.26 1.21v-2.31c.99.74 2.13 1.13 3.25 1.13s1.68-.45 1.68-1.23c0-.69-.39-.95-1.23-1.19l-1.19-.34c-1.78-.48-2.65-1.46-2.65-3.1 0-1.95 1.5-3.18 3.87-3.18 1.05 0 2.09.21 2.91.66v2.26a5.53 5.53 0 0 0-2.96-.84c-.92 0-1.57.35-1.57 1.06.01.6.39.91 1.16 1.12l1.32.39c1.82.5 2.61 1.42 2.61 3.07 0 2.1-1.53 3.39-3.82 3.39a6.08 6.08 0 0 1-3.38-.9Zm12.22-10.02h2.83l3.67 10.72h-2.28l-.83-2.55h-4.02l-.83 2.55h-2.2l3.66-10.72Zm2.76 6.25-1.39-4.24-1.37 4.24h2.76Zm5.72-6.25h2.19v8.61h4.73v2.1h-6.92v-10.72Zm9.06 10.02v-2.31c.99.74 2.13 1.13 3.25 1.13s1.68-.45 1.68-1.23c0-.69-.39-.95-1.23-1.19l-1.19-.34c-1.78-.48-2.65-1.46-2.65-3.1 0-1.95 1.5-3.18 3.87-3.18 1.05 0 2.09.21 2.91.66v2.26a5.53 5.53 0 0 0-2.96-.84c-.92 0-1.57.35-1.57 1.06.01.6.39.91 1.16 1.12l1.32.39c1.82.5 2.61 1.42 2.61 3.07 0 2.1-1.53 3.39-3.82 3.39a6.08 6.08 0 0 1-3.38-.9ZM30 199.28h2.94l4.03 8.17v-8.17h2.07V210h-2.93l-4.03-8.17V210h-2.09v-10.72Zm14.7 0h2.83L51.2 210h-2.28l-.83-2.55h-4.02l-.83 2.55h-2.2l3.66-10.72Zm2.76 6.25-1.39-4.24-1.37 4.24h2.76Zm5.72-6.25h3.28l2.49 8.21 2.45-8.21h3.33V210h-2.04v-8.62L59.96 210h-2.07l-2.7-8.47V210h-2v-10.72Zm14.43 0h6.93v2.06h-4.79v2.23h4.45v2.06h-4.45v2.31h4.89V210h-7.03v-10.72Z" /><path d="M239.24 24.83h3.04c1.7 0 2.82 1 2.82 2.55 0 2.1-1.27 3.32-3.57 3.32h-1.97l-.71 3.3h-1.56l1.96-9.17Zm2.34 4.38c1.23 0 1.88-.58 1.88-1.68 0-.73-.49-1.2-1.48-1.2h-1.51l-.6 2.88h1.7Zm3.57 1.86c0-2.27 1.44-3.83 3.57-3.83 1.82 0 3.06 1.25 3.06 3.09 0 2.28-1.43 3.83-3.57 3.83-1.82 0-3.06-1.25-3.06-3.09Zm3.13 1.74c1.19 0 1.93-1.02 1.93-2.52 0-1.06-.62-1.69-1.56-1.69-1.19 0-1.93 1.02-1.93 2.52 0 1.06.62 1.69 1.56 1.69Zm4.74-5.41h1.49l.28 4.73 2.25-4.73h1.64l.23 4.77 2.25-4.77h1.56l-3.3 6.61h-1.62l-.25-5.04-2.42 5.04h-1.63l-.48-6.61Zm9.54 3.66c0-2.27 1.45-3.81 3.6-3.81 2 0 3.05 1.58 2.33 3.92h-4.46c0 1.1.81 1.68 2.05 1.68.8 0 1.45-.2 2.1-.59l-.31 1.46a4.2 4.2 0 0 1-2.04.44c-2.06 0-3.26-1.19-3.26-3.11Zm4.7-1.07c.12-.86-.31-1.46-1.22-1.46s-1.57.61-1.82 1.46h3.05Zm3.46-2.59h1.55l-.28 1.28c.81-1.7 2.56-1.36 2.77-1.29l-.35 1.46c-.18-.06-2.3-.63-2.82 1.68l-.74 3.48h-1.55l1.42-6.61Zm3.91 3.66c0-2.27 1.45-3.81 3.6-3.81 2 0 3.05 1.58 2.33 3.92h-4.46c0 1.1.81 1.68 2.05 1.68.8 0 1.45-.2 2.1-.59l-.31 1.46a4.2 4.2 0 0 1-2.04.44c-2.06 0-3.26-1.19-3.26-3.11Zm4.7-1.07c.12-.86-.31-1.46-1.22-1.46s-1.57.61-1.82 1.46h3.05Zm2.25 1.36c0-2.44 1.36-4.1 3.26-4.1 1 0 1.76.53 2.05 1.31l.79-3.72h1.55l-1.96 9.17h-1.55l.2-.92a2.15 2.15 0 0 1-1.92 1.08c-1.49 0-2.43-1.18-2.43-2.82Zm3 1.51c.88 0 1.51-.58 1.73-1.56l.17-.81c.24-1.1-.31-1.93-1.36-1.93-1.19 0-1.94 1.08-1.94 2.59 0 1.06.55 1.71 1.4 1.71Zm9.6-.01-.25 1.16h-1.55l1.96-9.17h1.55l-.73 3.47a2.35 2.35 0 0 1 1.99-1.05c1.49 0 2.35 1.16 2.35 2.76 0 2.52-1.36 4.16-3.21 4.16-.98 0-1.81-.53-2.1-1.32Zm1.83.01c1.16 0 1.87-1.06 1.87-2.61 0-1.04-.5-1.69-1.39-1.69s-1.52.56-1.73 1.55l-.17.79c-.24 1.14.34 1.97 1.42 1.97Zm5.68 1.16-1.04-6.62h1.52l.66 4.75 2.66-4.75h1.69l-5.31 9.13h-1.73l1.55-2.51Zm23.47-6.8c.91-.79 2.6-2.21 4.83-3.66a42.5 42.5 0 0 1 4.83 3.66c.23 1.18.62 3.36.75 6.01a43.12 43.12 0 0 1-5.58 2.35 42.54 42.54 0 0 1-5.58-2.35c.14-2.65.53-4.83.75-6.01Zm13.07-7.95s.82-.29 1.76-.45a14.9 14.9 0 0 0-9.53-3.81c.66.71 1.28 1.67 1.84 2.75 1.84.22 4.07.7 5.92 1.51Zm-2.71 18.36c-2.06-.4-4.05-.97-5.53-1.51a38.65 38.65 0 0 1-5.53 1.51c.12 1.5.35 3.04.76 4.58 0 0 1.54 1.82 4.78 2.8 3.23-.98 4.78-2.8 4.78-2.8.4-1.53.64-3.08.76-4.58Zm-13.77-18.37a22.3 22.3 0 0 1 5.93-1.51 12.4 12.4 0 0 1 1.84-2.75 14.97 14.97 0 0 0-9.53 3.81c.95.16 1.76.45 1.76.45Zm-4.72 8.77a25.74 25.74 0 0 0 3.58 2.94 37.48 37.48 0 0 1 4.08-4.04c.27-1.56.77-3.57 1.46-5.55a25.24 25.24 0 0 0-4.34-1.63s-2.35.42-4.81 2.74c-.77 3.29.04 5.54.04 5.54Zm25.92 0s.81-2.25.04-5.54c-2.46-2.31-4.81-2.74-4.81-2.74-1.53.42-2.99.99-4.34 1.63a37.79 37.79 0 0 1 1.46 5.55 37.44 37.44 0 0 1 4.08 4.04 25.86 25.86 0 0 0 3.58-2.94Zm-26.38.2s-.66-.56-1.27-1.3c-.7 3.34-.27 6.93 1.46 10.16.28-.93.8-1.94 1.46-2.97a22.32 22.32 0 0 1-1.66-5.88Zm8.24 14.27a22.07 22.07 0 0 1-4.27-4.38c-1.22.06-2.36 0-3.3-.22a14.91 14.91 0 0 0 8.07 6.34c-.34-.9-.5-1.75-.5-1.75Zm18.6-14.27s.66-.56 1.27-1.3c.7 3.34.27 6.93-1.46 10.16-.28-.93-.8-1.94-1.46-2.97a22.32 22.32 0 0 0 1.66-5.88Zm-8.24 14.27a22.07 22.07 0 0 0 4.27-4.38c1.22.06 2.36 0 3.3-.22a14.91 14.91 0 0 1-8.07 6.34c.34-.9.5-1.75.5-1.75Zm-5.18-25.66-4.12 2.45 1.26 3.91h5.72l1.26-3.91-4.12-2.45Zm-11.4 19.74 4.18 2.35 2.75-3.05-2.86-4.95-4.02.86-.06 4.79Zm22.79 0-.06-4.79-4.02-.86-2.86 4.95 2.75 3.05 4.18-2.35Z" style="fill:#00c1fa"/><path d="M106.67 109.1a304.9 304.9 0 0 0-3.72-10.89c5.04-5.53 35.28-40.74 24.54-68.91 10.57 10.67 8.19 28.85 3.59 41.95-4.79 13.14-13.43 26.48-24.4 37.84Zm30.89 20.82c-5.87 6.12-20.46 17.92-21.67 18.77a99.37 99.37 0 0 0 7.94 6.02 133.26 133.26 0 0 0 20.09-18.48 353.47 353.47 0 0 0-6.36-6.31Zm-29.65-16.74a380.9 380.9 0 0 1 3.13 11.56c-4.8-1.37-8.66-2.53-12.36-3.82a123.4 123.4 0 0 1-21.16 13.21l15.84 5.47c14.83-8.23 28.13-20.82 37.81-34.68 0 0 8.56-12.55 12.42-23.68 2.62-7.48 4.46-16.57 3.49-24.89-2.21-12.27-6.95-15.84-9.32-17.66 6.16 5.72 3.25 27.8-2.79 39.89-6.08 12.16-15.73 24.27-27.05 34.59Zm59.05-37.86c-.03 7.72-3.05 15.69-6.44 22.69 1.7 2.2 3.18 4.36 4.42 6.49 7.97-16.51 3.74-26.67 2.02-29.18ZM61.18 128.51l12.5 4.3a101.45 101.45 0 0 0 21.42-13.19 163.26 163.26 0 0 1-10.61-4.51 101.28 101.28 0 0 1-23.3 13.4Zm87.78-42.73c.86.77 5.44 5.18 6.75 6.59 6.39-16.61.78-28.86-1.27-30.56.72 8.05-2.02 16.51-5.48 23.98Zm-14.29 40.62-2.47-15.18a142.42 142.42 0 0 1-35.74 29.45c6.81 2.36 12.69 4.4 15.45 5.38a115.98 115.98 0 0 0 22.75-19.66Zm-42.62 34.73c4.48 2.93 12.94 4.24 18.8 1.23 6.03-3.84-.6-8.34-8.01-9.88-9.8-2.03-16.82 1.22-13.4 6.21.41.6 1.19 1.5 2.62 2.44m-1.84.4c-3.56-2.37-6.77-7.2-.23-10.08 10.41-3.43 28.39 3.2 24.99 9.22-.58 1.04-1.46 1.6-2.38 2.19h-.03v.02h-.03v.02h-.03c-7.04 3.65-17.06 2.13-22.3-1.36m5.48-3.86a4.94 4.94 0 0 0 5.06.49l1.35-.74-4.68-2.38-1.47.79c-.38.22-1.53.88-.26 1.84m-1.7.59c-2.35-1.57-.78-2.61-.02-3.11 1.09-.57 2.19-1.15 3.28-1.77 6.95 3.67 7.22 3.81 13.19 6.17l-1.38.81c-1.93-.78-4.52-1.82-6.42-2.68.86 1.4 1.99 3.27 2.9 4.64l-1.68.87c-.75-1.28-1.76-2.99-2.47-4.29-3.19 2.06-6.99-.36-7.42-.64" style="fill:url(#f2)"/><path d="M159.13 52.37C143.51 24.04 119.45 15 103.6 15c-11.92 0-25.97 5.78-36.84 13.17 9.54 4.38 21.86 15.96 22.02 16.11-7.94-3.05-17.83-6.72-33.23-7.87a135.1 135.1 0 0 0-19.77 20.38c.77 7.66 2.88 15.68 2.88 15.68-6.28-4.75-11.02-4.61-18 9.45-5.4 12.66-6.93 24.25-4.65 33.18 0 0 4.72 26.8 36.23 40.07-1.3-4.61-1.58-9.91-.93-15.73a87.96 87.96 0 0 1-15.63-9.87c.79-6.61 2.79-13.82 6-21.36 4.42-10.66 4.35-15.14 4.35-15.19.03.07 5.48 12.43 12.95 22.08 4.23-8.84 9.46-16.08 13.67-21.83l-3.77-6.75a143.73 143.73 0 0 1 18.19-18.75c2.05 1.07 4.79 2.47 6.84 3.58 8.68-7.27 19.25-14.05 30.56-18.29-7-11.49-16.02-19.27-16.02-19.27s27.7 2.74 42.02 15.69a25.8 25.8 0 0 1 8.65 2.89ZM28.58 107.52a70.1 70.1 0 0 0-2.74 12.52 55.65 55.65 0 0 1-6.19-8.84 69.17 69.17 0 0 1 2.65-12.1c1.77-5.31 3.35-5.91 5.86-2.23v-.05c2.14 3.07 1.81 6.14.42 10.7ZM61.69 72.2l-.05.05a221.85 221.85 0 0 1-7.77-18.1l.14-.14a194.51 194.51 0 0 1 18.56 6.98 144.44 144.44 0 0 0-10.88 11.22Zm54.84-47.38c-4.42.7-9.02 1.95-13.67 3.72a65.03 65.03 0 0 0-7.81-5.31 66.04 66.04 0 0 1 13.02-3.54c1.53-.19 6.23-.79 10.32 2.42v-.05c2.47 1.91.14 2.37-1.86 2.75Z" style="fill:url(#h)"/>'
        ));
    }

    /// @notice Transfer ownership to a new owner.
    /// @param newOwner The address to transfer ownership to.
    function transferOwnership(address newOwner) external onlyOwner {
        emit OwnershipTransferred(owner, newOwner);
        owner = newOwner;
    }

    /// @notice Write data to be accessed by a given file key.
    /// @param key The key to access the written data.
    /// @param data The data to be written.
    function writeFile(uint256 key, string memory data) external onlyOwner {
        files[key] = SSTORE2.write(bytes(data));
    }

    /// @notice Read data using a given file key.
    /// @param key The key to access the stored data.
    /// @return data The data stored at the given key.
    function readFile(uint256 key) external view returns (string memory data) {
        return string(SSTORE2.read(files[key]));
    }

    /// @notice Create or set a customization preset for renderers to use.
    /// @param id The ID of the customization preset.
    /// @param customizationData Data decoded by renderers used to render the SVG according to the preset.
    function createCustomizationPreset(uint256 id, bytes memory customizationData) external onlyOwner {
        customizationPresets[id] = customizationData;
    }

    /// @notice For crowdfund or party instances to set the customization preset they want to use.
    /// @param id The ID of the customization preset.
    function useCustomizationPreset(uint256 id) external {
        getPresetFor[msg.sender] = id;
    }
}

File 13 of 30 : ERC1155Receiver.sol
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8;

import "../vendor/solmate/ERC1155.sol";
import "../utils/EIP165.sol";

abstract contract ERC1155Receiver is EIP165, ERC1155TokenReceiverBase {
    /// @inheritdoc EIP165
    function supportsInterface(bytes4 interfaceId)
        public
        override
        virtual
        pure
        returns (bool)
    {
        return super.supportsInterface(interfaceId) ||
            interfaceId == type(ERC1155TokenReceiverBase).interfaceId;
    }

}

File 14 of 30 : ERC721Receiver.sol
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8;

import "./IERC721Receiver.sol";
import "../utils/EIP165.sol";
import "../vendor/solmate/ERC721.sol";

/// @notice Mixin for contracts that want to receive ERC721 tokens.
/// @dev Use this instead of solmate's ERC721TokenReceiver because the
///      compiler has issues when overriding EIP165/IERC721Receiver functions.
abstract contract ERC721Receiver is IERC721Receiver, EIP165, ERC721TokenReceiver {
    /// @inheritdoc IERC721Receiver
    function onERC721Received(address, address, uint256, bytes memory)
        public
        virtual
        override(IERC721Receiver, ERC721TokenReceiver)
        returns (bytes4)
    {
        return IERC721Receiver.onERC721Received.selector;
    }

    /// @inheritdoc EIP165
    function supportsInterface(bytes4 interfaceId)
        public
        pure
        virtual
        override
        returns (bool)
    {
        return EIP165.supportsInterface(interfaceId) ||
            interfaceId == type(IERC721Receiver).interfaceId;
    }
}

File 15 of 30 : IERC1155.sol
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8;

// Minimal ERC1155 interface.
interface IERC1155 {
    event TransferSingle(
        address indexed operator,
        address indexed from,
        address indexed to,
        uint256 id,
        uint256 amount
    );
    event TransferBatch(
        address indexed operator,
        address indexed from,
        address indexed to,
        uint256[] ids,
        uint256[] amounts
    );
    event ApprovalForAll(address indexed owner, address indexed operator, bool approved);

    function setApprovalForAll(address operator, bool approved) external;
    function safeTransferFrom(
        address from,
        address to,
        uint256 id,
        uint256 amount,
        bytes calldata data
    ) external;
    function safeBatchTransferFrom(
        address from,
        address to,
        uint256[] calldata ids,
        uint256[] calldata amounts,
        bytes calldata data
    ) external;
    function balanceOf(address owner, uint256 tokenId) external view returns (uint256);
    function isApprovedForAll(address owner, address spender) external view returns (bool);
    function balanceOfBatch(address[] calldata owners, uint256[] calldata ids)
        external
        view
        returns (uint256[] memory balances);
}

File 16 of 30 : IERC20.sol
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8;

// Minimal ERC20 interface.
interface IERC20 {
    event Transfer(address indexed owner, address indexed to, uint256 amount);
    event Approval(address indexed owner, address indexed spender, uint256 allowance);

    function transfer(address to, uint256 amount) external returns (bool);
    function transferFrom(address from, address to, uint256 amount) external returns (bool);
    function approve(address spender, uint256 allowance) external returns (bool);
    function allowance(address owner, address spender) external view returns (uint256);
    function balanceOf(address owner) external view returns (uint256);
}

File 17 of 30 : IERC721.sol
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8;

// Minimal ERC721 interface.
interface IERC721 {
    event Transfer(address indexed owner, address indexed to, uint256 indexed tokenId);
    event Approval(address indexed owner, address indexed operator, uint256 indexed tokenId);
    event ApprovalForAll(address indexed owner, address indexed operator, bool approved);

    function transferFrom(address from, address to, uint256 tokenId) external;
    function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external;
    function safeTransferFrom(address from, address to, uint256 tokenId) external;
    function approve(address operator, uint256 tokenId) external;
    function setApprovalForAll(address operator, bool isApproved) external;
    function name() external view returns (string memory);
    function symbol() external view returns (string memory);
    function getApproved(uint256 tokenId) external view returns (address);
    function isApprovedForAll(address owner, address operator) external view returns (bool);
    function ownerOf(uint256 tokenId) external view returns (address);
    function balanceOf(address owner) external view returns (uint256);
}

File 18 of 30 : IERC721Receiver.sol
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8;

interface IERC721Receiver {

    function onERC721Received(
        address operator,
        address from,
        uint256 tokenId,
        bytes memory data
    ) external returns (bytes4);
}

File 19 of 30 : EIP165.sol
// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.17;

abstract contract EIP165 {
    /// @notice Query if a contract implements an interface.
    /// @param interfaceId The interface identifier, as specified in ERC-165
    /// @return `true` if the contract implements `interfaceId` and
    ///         `interfaceId` is not 0xffffffff, `false` otherwise
    function supportsInterface(bytes4 interfaceId)
        public
        virtual
        pure
        returns (bool)
    {
        return interfaceId == this.supportsInterface.selector;
    }
}

File 20 of 30 : Implementation.sol
// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.17;

// Base contract for all contracts intended to be delegatecalled into.
abstract contract Implementation {
    error OnlyDelegateCallError();
    error OnlyConstructorError();

    address public immutable IMPL;

    constructor() { IMPL = address(this); }

    // Reverts if the current function context is not inside of a delegatecall.
    modifier onlyDelegateCall() virtual {
        if (address(this) == IMPL) {
            revert OnlyDelegateCallError();
        }
        _;
    }

    // Reverts if the current function context is not inside of a constructor.
    modifier onlyConstructor() {
        uint256 codeSize;
        assembly { codeSize := extcodesize(address()) }
        if (codeSize != 0) {
            revert OnlyConstructorError();
        }
        _;
    }
}

File 21 of 30 : LibERC20Compat.sol
// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.17;

import "../tokens/IERC20.sol";

// Compatibility helpers for ERC20s.
library LibERC20Compat {
    error NotATokenError(IERC20 token);
    error TokenTransferFailedError(IERC20 token, address to, uint256 amount);

    // Perform an `IERC20.transfer()` handling non-compliant implementations.
    function compatTransfer(IERC20 token, address to, uint256 amount)
        internal
    {
        (bool s, bytes memory r) =
            address(token).call(abi.encodeCall(IERC20.transfer, (to, amount)));
        if (s) {
            if (r.length == 0) {
                uint256 cs;
                assembly { cs := extcodesize(token) }
                if (cs == 0) {
                    revert NotATokenError(token);
                }
                return;
            }
            if (abi.decode(r, (bool))) {
                return;
            }
        }
        revert TokenTransferFailedError(token, to, amount);
    }
}

File 22 of 30 : LibRawResult.sol
// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.17;

library LibRawResult {
    // Revert with the data in `b`.
    function rawRevert(bytes memory b)
        internal
        pure
    {
        assembly { revert(add(b, 32), mload(b)) }
    }

    // Return with the data in `b`.
    function rawReturn(bytes memory b)
        internal
        pure
    {
        assembly { return(add(b, 32), mload(b)) }
    }
}

File 23 of 30 : LibSafeCast.sol
// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.17;

library LibSafeCast {
    error Uint256ToUint96CastOutOfRange(uint256 v);
    error Uint256ToInt192CastOutOfRange(uint256 v);
    error Int192ToUint96CastOutOfRange(int192 i192);
    error Uint256ToInt128CastOutOfRangeError(uint256 u256);
    error Uint256ToUint128CastOutOfRangeError(uint256 u256);
    error Uint256ToUint40CastOutOfRangeError(uint256 u256);

    function safeCastUint256ToUint96(uint256 v) internal pure returns (uint96) {
        if (v > uint256(type(uint96).max)) {
            revert Uint256ToUint96CastOutOfRange(v);
        }
        return uint96(v);
    }

    function safeCastUint256ToUint128(uint256 v) internal pure returns (uint128) {
        if (v > uint256(type(uint128).max)) {
            revert Uint256ToUint128CastOutOfRangeError(v);
        }
        return uint128(v);
    }

    function safeCastUint256ToInt192(uint256 v) internal pure returns (int192) {
        if (v > uint256(uint192(type(int192).max))) {
            revert Uint256ToInt192CastOutOfRange(v);
        }
        return int192(uint192(v));
    }

    function safeCastUint96ToInt192(uint96 v) internal pure returns (int192) {
        return int192(uint192(v));
    }

    function safeCastInt192ToUint96(int192 i192) internal pure returns (uint96) {
        if (i192 < 0 || i192 > int192(uint192(type(uint96).max))) {
            revert Int192ToUint96CastOutOfRange(i192);
        }
        return uint96(uint192(i192));
    }

    function safeCastUint256ToInt128(uint256 x)
        internal
        pure
        returns (int128)
    {
        if (x > uint256(uint128(type(int128).max))) {
            revert Uint256ToInt128CastOutOfRangeError(x);
        }
        return int128(uint128(x));
    }

    function safeCastUint256ToUint40(uint256 x)
        internal
        pure
        returns (uint40)
    {
        if (x > uint256(type(uint40).max)) {
            revert Uint256ToUint40CastOutOfRangeError(x);
        }
        return uint40(x);
    }
}

File 24 of 30 : Multicall.sol
// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.17;

import "../utils/LibRawResult.sol";

abstract contract Multicall {
    using LibRawResult for bytes;

    /// @notice Perform multiple delegatecalls on ourselves.
    function multicall(bytes[] calldata multicallData) external {
        for (uint256 i; i < multicallData.length; ++i) {
            (bool s, bytes memory r) = address(this).delegatecall(multicallData[i]);
            if (!s) {
                r.rawRevert();
            }
        }
    }
}

File 25 of 30 : ReadOnlyDelegateCall.sol
// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.17;

import "./LibRawResult.sol";

interface IReadOnlyDelegateCall {
    // Marked `view` so that `_readOnlyDelegateCall` can be `view` as well.
    function delegateCallAndRevert(address impl, bytes memory callData)
        external
        view;
}

// Inherited by contracts to perform read-only delegate calls.
abstract contract ReadOnlyDelegateCall {
    using LibRawResult for bytes;

    // Delegatecall into implement and revert with the raw result.
    function delegateCallAndRevert(address impl, bytes memory callData) external {
        // Attempt to gate to only `_readOnlyDelegateCall()` invocations.
        require(msg.sender == address(this));
        (bool s, bytes memory r) = impl.delegatecall(callData);
        // Revert with success status and return data.
        abi.encode(s, r).rawRevert();
    }

    // Perform a `delegateCallAndRevert()` then return the raw result data.
    function _readOnlyDelegateCall(address impl, bytes memory callData) internal view {
        try IReadOnlyDelegateCall(address(this)).delegateCallAndRevert(impl, callData) {
            // Should never happen.
            assert(false);
        }
        catch (bytes memory r) {
            (bool success, bytes memory resultData) = abi.decode(r, (bool, bytes));
            if (!success) {
                resultData.rawRevert();
            }
            resultData.rawReturn();
        }
    }
}

File 26 of 30 : ERC1155.sol
// SPDX-License-Identifier: AGPL-3.0-only
// Based on solmate commit 1681dc505f4897ef636f0435d01b1aa027fdafaf (v6.4.0)
//  @ https://github.com/Rari-Capital/solmate/blob/1681dc505f4897ef636f0435d01b1aa027fdafaf/src/tokens/ERC1155.sol
// Only modified to inherit IERC1155 and rename ERC1155TokenReceiver -> ERC1155TokenReceiverBase.
pragma solidity ^0.8;

import "../../tokens/IERC1155.sol";

/// @notice Minimalist and gas efficient standard ERC1155 implementation.
/// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/tokens/ERC1155.sol)
abstract contract ERC1155 is IERC1155 {
    /*//////////////////////////////////////////////////////////////
                                 EVENTS
    //////////////////////////////////////////////////////////////*/

    event URI(string value, uint256 indexed id);

    /*//////////////////////////////////////////////////////////////
                             ERC1155 STORAGE
    //////////////////////////////////////////////////////////////*/

    mapping(address => mapping(uint256 => uint256)) public balanceOf;

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

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

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

    /*//////////////////////////////////////////////////////////////
                              ERC1155 LOGIC
    //////////////////////////////////////////////////////////////*/

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

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

    function safeTransferFrom(
        address from,
        address to,
        uint256 id,
        uint256 amount,
        bytes calldata data
    ) public virtual {
        require(msg.sender == from || isApprovedForAll[from][msg.sender], "NOT_AUTHORIZED");

        balanceOf[from][id] -= amount;
        balanceOf[to][id] += amount;

        emit TransferSingle(msg.sender, from, to, id, amount);

        require(
            to.code.length == 0
                ? to != address(0)
                : ERC1155TokenReceiverBase(to).onERC1155Received(msg.sender, from, id, amount, data) ==
                    ERC1155TokenReceiverBase.onERC1155Received.selector,
            "UNSAFE_RECIPIENT"
        );
    }

    function safeBatchTransferFrom(
        address from,
        address to,
        uint256[] calldata ids,
        uint256[] calldata amounts,
        bytes calldata data
    ) public virtual {
        require(ids.length == amounts.length, "LENGTH_MISMATCH");

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

        // Storing these outside the loop saves ~15 gas per iteration.
        uint256 id;
        uint256 amount;

        for (uint256 i; i < ids.length; ) {
            id = ids[i];
            amount = amounts[i];

            balanceOf[from][id] -= amount;
            balanceOf[to][id] += amount;

            // An array can't have a total length
            // larger than the max uint256 value.
            unchecked {
                ++i;
            }
        }

        emit TransferBatch(msg.sender, from, to, ids, amounts);

        require(
            to.code.length == 0
                ? to != address(0)
                : ERC1155TokenReceiverBase(to).onERC1155BatchReceived(msg.sender, from, ids, amounts, data) ==
                    ERC1155TokenReceiverBase.onERC1155BatchReceived.selector,
            "UNSAFE_RECIPIENT"
        );
    }

    function balanceOfBatch(address[] calldata owners, uint256[] calldata ids)
        public
        view
        virtual
        returns (uint256[] memory balances)
    {
        require(owners.length == ids.length, "LENGTH_MISMATCH");

        balances = new uint256[](owners.length);

        // Unchecked because the only math done is incrementing
        // the array index counter which cannot possibly overflow.
        unchecked {
            for (uint256 i; i < owners.length; ++i) {
                balances[i] = balanceOf[owners[i]][ids[i]];
            }
        }
    }

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

    function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {
        return
            interfaceId == 0x01ffc9a7 || // ERC165 Interface ID for ERC165
            interfaceId == 0xd9b67a26 || // ERC165 Interface ID for ERC1155
            interfaceId == 0x0e89341c; // ERC165 Interface ID for ERC1155MetadataURI
    }

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

    function _mint(
        address to,
        uint256 id,
        uint256 amount,
        bytes memory data
    ) internal virtual {
        balanceOf[to][id] += amount;

        emit TransferSingle(msg.sender, address(0), to, id, amount);

        require(
            to.code.length == 0
                ? to != address(0)
                : ERC1155TokenReceiverBase(to).onERC1155Received(msg.sender, address(0), id, amount, data) ==
                    ERC1155TokenReceiverBase.onERC1155Received.selector,
            "UNSAFE_RECIPIENT"
        );
    }

    function _batchMint(
        address to,
        uint256[] memory ids,
        uint256[] memory amounts,
        bytes memory data
    ) internal virtual {
        uint256 idsLength = ids.length; // Saves MLOADs.

        require(idsLength == amounts.length, "LENGTH_MISMATCH");

        for (uint256 i; i < idsLength; ) {
            balanceOf[to][ids[i]] += amounts[i];

            // An array can't have a total length
            // larger than the max uint256 value.
            unchecked {
                ++i;
            }
        }

        emit TransferBatch(msg.sender, address(0), to, ids, amounts);

        require(
            to.code.length == 0
                ? to != address(0)
                : ERC1155TokenReceiverBase(to).onERC1155BatchReceived(msg.sender, address(0), ids, amounts, data) ==
                    ERC1155TokenReceiverBase.onERC1155BatchReceived.selector,
            "UNSAFE_RECIPIENT"
        );
    }

    function _batchBurn(
        address from,
        uint256[] memory ids,
        uint256[] memory amounts
    ) internal virtual {
        uint256 idsLength = ids.length; // Saves MLOADs.

        require(idsLength == amounts.length, "LENGTH_MISMATCH");

        for (uint256 i; i < idsLength; ) {
            balanceOf[from][ids[i]] -= amounts[i];

            // An array can't have a total length
            // larger than the max uint256 value.
            unchecked {
                ++i;
            }
        }

        emit TransferBatch(msg.sender, from, address(0), ids, amounts);
    }

    function _burn(
        address from,
        uint256 id,
        uint256 amount
    ) internal virtual {
        balanceOf[from][id] -= amount;

        emit TransferSingle(msg.sender, from, address(0), id, amount);
    }
}

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

    function onERC1155BatchReceived(
        address,
        address,
        uint256[] calldata,
        uint256[] calldata,
        bytes calldata
    ) external virtual returns (bytes4) {
        return ERC1155TokenReceiverBase.onERC1155BatchReceived.selector;
    }
}

File 27 of 30 : ERC721.sol
// SPDX-License-Identifier: AGPL-3.0-only
// Based on solmate commit 1681dc505f4897ef636f0435d01b1aa027fdafaf (v6.4.0)
//  @ https://github.com/Rari-Capital/solmate/blob/1681dc505f4897ef636f0435d01b1aa027fdafaf/src/tokens/ERC1155.sol
// Only modified to inherit IERC721 and EIP165.
pragma solidity >=0.8.0;

// NOTE: Only modified to inherit IERC20 and EIP165
import "../../tokens/IERC721.sol";
import "../../utils/EIP165.sol";


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

    /*//////////////////////////////////////////////////////////////
                         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 pure virtual override returns (bool) {
        // NOTE: modified from original to call super.
        return super.supportsInterface(interfaceId) ||
            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/Rari-Capital/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 28 of 30 : IERC2981.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (interfaces/IERC2981.sol)

pragma solidity ^0.8.0;

import "../utils/introspection/IERC165.sol";

/**
 * @dev Interface for the NFT Royalty Standard.
 *
 * A standardized way to retrieve royalty payment information for non-fungible tokens (NFTs) to enable universal
 * support for royalty payments across all NFT marketplaces and ecosystem participants.
 *
 * _Available since v4.5._
 */
interface IERC2981 is IERC165 {
    /**
     * @dev Returns how much royalty is owed and to whom, based on a sale price that may be denominated in any unit of
     * exchange. The royalty amount is denominated and should be paid in that same unit of exchange.
     */
    function royaltyInfo(uint256 tokenId, uint256 salePrice)
        external
        view
        returns (address receiver, uint256 royaltyAmount);
}

File 29 of 30 : IERC165.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC165 standard, as defined in the
 * https://eips.ethereum.org/EIPS/eip-165[EIP].
 *
 * Implementers can declare support of contract interfaces, which can then be
 * queried by others ({ERC165Checker}).
 *
 * For an implementation, see {ERC165}.
 */
interface IERC165 {
    /**
     * @dev Returns true if this contract implements the interface defined by
     * `interfaceId`. See the corresponding
     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
     * to learn more about how these ids are created.
     *
     * This function call must use less than 30 000 gas.
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}

File 30 of 30 : SSTORE2.sol
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;

/// @notice Read and write to persistent storage at a fraction of the cost.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/SSTORE2.sol)
/// @author Modified from 0xSequence (https://github.com/0xSequence/sstore2/blob/master/contracts/SSTORE2.sol)
library SSTORE2 {
    uint256 internal constant DATA_OFFSET = 1; // We skip the first byte as it's a STOP opcode to ensure the contract can't be called.

    /*//////////////////////////////////////////////////////////////
                               WRITE LOGIC
    //////////////////////////////////////////////////////////////*/

    function write(bytes memory data) internal returns (address pointer) {
        // Prefix the bytecode with a STOP opcode to ensure it cannot be called.
        bytes memory runtimeCode = abi.encodePacked(hex"00", data);

        bytes memory creationCode = abi.encodePacked(
            //---------------------------------------------------------------------------------------------------------------//
            // Opcode  | Opcode + Arguments  | Description  | Stack View                                                     //
            //---------------------------------------------------------------------------------------------------------------//
            // 0x60    |  0x600B             | PUSH1 11     | codeOffset                                                     //
            // 0x59    |  0x59               | MSIZE        | 0 codeOffset                                                   //
            // 0x81    |  0x81               | DUP2         | codeOffset 0 codeOffset                                        //
            // 0x38    |  0x38               | CODESIZE     | codeSize codeOffset 0 codeOffset                               //
            // 0x03    |  0x03               | SUB          | (codeSize - codeOffset) 0 codeOffset                           //
            // 0x80    |  0x80               | DUP          | (codeSize - codeOffset) (codeSize - codeOffset) 0 codeOffset   //
            // 0x92    |  0x92               | SWAP3        | codeOffset (codeSize - codeOffset) 0 (codeSize - codeOffset)   //
            // 0x59    |  0x59               | MSIZE        | 0 codeOffset (codeSize - codeOffset) 0 (codeSize - codeOffset) //
            // 0x39    |  0x39               | CODECOPY     | 0 (codeSize - codeOffset)                                      //
            // 0xf3    |  0xf3               | RETURN       |                                                                //
            //---------------------------------------------------------------------------------------------------------------//
            hex"60_0B_59_81_38_03_80_92_59_39_F3", // Returns all code in the contract except for the first 11 (0B in hex) bytes.
            runtimeCode // The bytecode we want the contract to have after deployment. Capped at 1 byte less than the code size limit.
        );

        assembly {
            // Deploy a new contract with the generated creation code.
            // We start 32 bytes into the code to avoid copying the byte length.
            pointer := create(0, add(creationCode, 32), mload(creationCode))
        }

        require(pointer != address(0), "DEPLOYMENT_FAILED");
    }

    /*//////////////////////////////////////////////////////////////
                               READ LOGIC
    //////////////////////////////////////////////////////////////*/

    function read(address pointer) internal view returns (bytes memory) {
        return readBytecode(pointer, DATA_OFFSET, pointer.code.length - DATA_OFFSET);
    }

    function read(address pointer, uint256 start) internal view returns (bytes memory) {
        start += DATA_OFFSET;

        return readBytecode(pointer, start, pointer.code.length - start);
    }

    function read(
        address pointer,
        uint256 start,
        uint256 end
    ) internal view returns (bytes memory) {
        start += DATA_OFFSET;
        end += DATA_OFFSET;

        require(pointer.code.length >= end, "OUT_OF_BOUNDS");

        return readBytecode(pointer, start, end - start);
    }

    /*//////////////////////////////////////////////////////////////
                          INTERNAL HELPER LOGIC
    //////////////////////////////////////////////////////////////*/

    function readBytecode(
        address pointer,
        uint256 start,
        uint256 size
    ) private view returns (bytes memory data) {
        assembly {
            // Get a pointer to some free memory.
            data := mload(0x40)

            // Update the free memory pointer to prevent overriding our data.
            // We use and(x, not(31)) as a cheaper equivalent to sub(x, mod(x, 32)).
            // Adding 31 to size and running the result through the logic above ensures
            // the memory pointer remains word-aligned, following the Solidity convention.
            mstore(0x40, add(data, and(add(add(size, 32), 31), not(31))))

            // Store the size of the data in the first 32 byte chunk of free memory.
            mstore(data, size)

            // Copy the code into memory right after the 32 bytes we used to store the size.
            extcodecopy(pointer, add(data, 32), start, size)
        }
    }
}

Settings
{
  "remappings": [
    "ds-test/=lib/solmate/lib/ds-test/src/",
    "forge-std/=lib/forge-std/src/",
    "openzeppelin/=lib/openzeppelin-contracts/",
    "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":"contract IGlobals","name":"globals","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"voter","type":"address"}],"name":"AlreadyVotedError","type":"error"},{"inputs":[],"name":"BadPreciousListError","type":"error"},{"inputs":[{"internalType":"bytes32","name":"proposalHash","type":"bytes32"},{"internalType":"bytes32","name":"actualHash","type":"bytes32"}],"name":"BadProposalHashError","type":"error"},{"inputs":[{"internalType":"enum PartyGovernance.ProposalStatus","name":"status","type":"uint8"}],"name":"BadProposalStatusError","type":"error"},{"inputs":[{"internalType":"uint40","name":"maxExecutableTime","type":"uint40"},{"internalType":"uint40","name":"timestamp","type":"uint40"}],"name":"ExecutionTimeExceededError","type":"error"},{"inputs":[{"internalType":"int192","name":"i192","type":"int192"}],"name":"Int192ToUint96CastOutOfRange","type":"error"},{"inputs":[{"internalType":"uint16","name":"bps","type":"uint16"}],"name":"InvalidBpsError","type":"error"},{"inputs":[],"name":"InvalidDelegateError","type":"error"},{"inputs":[],"name":"InvalidNewHostError","type":"error"},{"inputs":[],"name":"MismatchedPreciousListLengths","type":"error"},{"inputs":[{"internalType":"contract IERC20","name":"token","type":"address"}],"name":"NotATokenError","type":"error"},{"inputs":[],"name":"OnlyActiveMemberError","type":"error"},{"inputs":[],"name":"OnlyConstructorError","type":"error"},{"inputs":[],"name":"OnlyDelegateCallError","type":"error"},{"inputs":[{"internalType":"address","name":"actual","type":"address"},{"internalType":"address","name":"expected","type":"address"}],"name":"OnlyMintAuthorityError","type":"error"},{"inputs":[{"internalType":"address","name":"notDao","type":"address"},{"internalType":"address","name":"partyDao","type":"address"}],"name":"OnlyPartyDaoError","type":"error"},{"inputs":[{"internalType":"address","name":"notDao","type":"address"},{"internalType":"address","name":"partyDao","type":"address"}],"name":"OnlyPartyDaoOrHostError","type":"error"},{"inputs":[],"name":"OnlyPartyHostError","type":"error"},{"inputs":[],"name":"OnlyWhenEmergencyActionsAllowedError","type":"error"},{"inputs":[],"name":"OnlyWhenEnabledError","type":"error"},{"inputs":[{"internalType":"uint40","name":"currentTime","type":"uint40"},{"internalType":"uint40","name":"cancelTime","type":"uint40"}],"name":"ProposalCannotBeCancelledYetError","type":"error"},{"inputs":[{"internalType":"contract IERC20","name":"token","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"TokenTransferFailedError","type":"error"},{"inputs":[{"internalType":"uint256","name":"v","type":"uint256"}],"name":"Uint256ToInt192CastOutOfRange","type":"error"},{"inputs":[{"internalType":"uint256","name":"v","type":"uint256"}],"name":"Uint256ToUint96CastOutOfRange","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","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":"enum ITokenDistributor.TokenType","name":"tokenType","type":"uint8"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"DistributionCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"target","type":"address"},{"indexed":false,"internalType":"bytes","name":"data","type":"bytes"},{"indexed":false,"internalType":"uint256","name":"amountEth","type":"uint256"}],"name":"EmergencyExecute","type":"event"},{"anonymous":false,"inputs":[],"name":"EmergencyExecuteDisabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldHost","type":"address"},{"indexed":false,"internalType":"address","name":"newHost","type":"address"}],"name":"HostStatusTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"proposalId","type":"uint256"},{"indexed":false,"internalType":"address","name":"voter","type":"address"},{"indexed":false,"internalType":"uint256","name":"weight","type":"uint256"}],"name":"ProposalAccepted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"proposalId","type":"uint256"}],"name":"ProposalCancelled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"proposalId","type":"uint256"},{"indexed":false,"internalType":"address","name":"executor","type":"address"},{"indexed":false,"internalType":"bytes","name":"nextProgressData","type":"bytes"}],"name":"ProposalExecuted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"proposalId","type":"uint256"}],"name":"ProposalPassed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"proposalId","type":"uint256"},{"indexed":false,"internalType":"address","name":"host","type":"address"}],"name":"ProposalVetoed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"proposalId","type":"uint256"},{"indexed":false,"internalType":"address","name":"proposer","type":"address"},{"components":[{"internalType":"uint40","name":"maxExecutableTime","type":"uint40"},{"internalType":"uint40","name":"cancelDelay","type":"uint40"},{"internalType":"bytes","name":"proposalData","type":"bytes"}],"indexed":false,"internalType":"struct PartyGovernance.Proposal","name":"proposal","type":"tuple"}],"name":"Proposed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"delegate","type":"address"}],"name":"VotingPowerDelegated","type":"event"},{"stateMutability":"nonpayable","type":"fallback"},{"inputs":[],"name":"IMPL","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"abdicate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newPartyHost","type":"address"}],"name":"abdicate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"proposalId","type":"uint256"},{"internalType":"uint256","name":"snapIndex","type":"uint256"}],"name":"accept","outputs":[{"internalType":"uint256","name":"totalVotes","type":"uint256"}],"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":[{"internalType":"uint256","name":"proposalId","type":"uint256"},{"components":[{"internalType":"uint40","name":"maxExecutableTime","type":"uint40"},{"internalType":"uint40","name":"cancelDelay","type":"uint40"},{"internalType":"bytes","name":"proposalData","type":"bytes"}],"internalType":"struct PartyGovernance.Proposal","name":"proposal","type":"tuple"}],"name":"cancel","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"contractURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"impl","type":"address"},{"internalType":"bytes","name":"callData","type":"bytes"}],"name":"delegateCallAndRevert","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"delegate","type":"address"}],"name":"delegateVotingPower","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"delegationsByVoter","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"disableEmergencyExecute","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"enum ITokenDistributor.TokenType","name":"tokenType","type":"uint8"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"distribute","outputs":[{"components":[{"internalType":"enum ITokenDistributor.TokenType","name":"tokenType","type":"uint8"},{"internalType":"uint256","name":"distributionId","type":"uint256"},{"internalType":"contract ITokenDistributorParty","name":"party","type":"address"},{"internalType":"address payable","name":"feeRecipient","type":"address"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint128","name":"memberSupply","type":"uint128"},{"internalType":"uint128","name":"fee","type":"uint128"}],"internalType":"struct ITokenDistributor.DistributionInfo","name":"distInfo","type":"tuple"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"targetAddress","type":"address"},{"internalType":"bytes","name":"targetCallData","type":"bytes"},{"internalType":"uint256","name":"amountEth","type":"uint256"}],"name":"emergencyExecute","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"emergencyExecuteDisabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"proposalId","type":"uint256"},{"components":[{"internalType":"uint40","name":"maxExecutableTime","type":"uint40"},{"internalType":"uint40","name":"cancelDelay","type":"uint40"},{"internalType":"bytes","name":"proposalData","type":"bytes"}],"internalType":"struct PartyGovernance.Proposal","name":"proposal","type":"tuple"},{"internalType":"contract IERC721[]","name":"preciousTokens","type":"address[]"},{"internalType":"uint256[]","name":"preciousTokenIds","type":"uint256[]"},{"internalType":"bytes","name":"progressData","type":"bytes"},{"internalType":"bytes","name":"extraData","type":"bytes"}],"name":"execute","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"feeBps","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"feeRecipient","outputs":[{"internalType":"address payable","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"voter","type":"address"},{"internalType":"uint40","name":"timestamp","type":"uint40"}],"name":"findVotingPowerSnapshotIndex","outputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getDistributionShareOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getGovernanceValues","outputs":[{"components":[{"internalType":"uint40","name":"voteDuration","type":"uint40"},{"internalType":"uint40","name":"executionDelay","type":"uint40"},{"internalType":"uint16","name":"passThresholdBps","type":"uint16"},{"internalType":"uint96","name":"totalVotingPower","type":"uint96"}],"internalType":"struct PartyGovernance.GovernanceValues","name":"gv","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getProposalExecutionEngine","outputs":[{"internalType":"contract IProposalExecutionEngine","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint40","name":"maxExecutableTime","type":"uint40"},{"internalType":"uint40","name":"cancelDelay","type":"uint40"},{"internalType":"bytes","name":"proposalData","type":"bytes"}],"internalType":"struct PartyGovernance.Proposal","name":"proposal","type":"tuple"}],"name":"getProposalHash","outputs":[{"internalType":"bytes32","name":"proposalHash","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"proposalId","type":"uint256"}],"name":"getProposalStateInfo","outputs":[{"internalType":"enum PartyGovernance.ProposalStatus","name":"status","type":"uint8"},{"components":[{"internalType":"uint40","name":"proposedTime","type":"uint40"},{"internalType":"uint40","name":"passedTime","type":"uint40"},{"internalType":"uint40","name":"executedTime","type":"uint40"},{"internalType":"uint40","name":"completedTime","type":"uint40"},{"internalType":"uint96","name":"votes","type":"uint96"}],"internalType":"struct PartyGovernance.ProposalStateValues","name":"values","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"voter","type":"address"},{"internalType":"uint40","name":"timestamp","type":"uint40"}],"name":"getVotingPowerAt","outputs":[{"internalType":"uint96","name":"votingPower","type":"uint96"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"voter","type":"address"},{"internalType":"uint40","name":"timestamp","type":"uint40"},{"internalType":"uint256","name":"snapIndex","type":"uint256"}],"name":"getVotingPowerAt","outputs":[{"internalType":"uint96","name":"votingPower","type":"uint96"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"components":[{"components":[{"internalType":"address[]","name":"hosts","type":"address[]"},{"internalType":"uint40","name":"voteDuration","type":"uint40"},{"internalType":"uint40","name":"executionDelay","type":"uint40"},{"internalType":"uint16","name":"passThresholdBps","type":"uint16"},{"internalType":"uint96","name":"totalVotingPower","type":"uint96"},{"internalType":"uint16","name":"feeBps","type":"uint16"},{"internalType":"address payable","name":"feeRecipient","type":"address"}],"internalType":"struct PartyGovernance.GovernanceOpts","name":"governance","type":"tuple"},{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"symbol","type":"string"},{"internalType":"uint256","name":"customizationPresetId","type":"uint256"}],"internalType":"struct Party.PartyOptions","name":"options","type":"tuple"},{"internalType":"contract IERC721[]","name":"preciousTokens","type":"address[]"},{"internalType":"uint256[]","name":"preciousTokenIds","type":"uint256[]"},{"internalType":"address","name":"mintAuthority","type":"address"}],"internalType":"struct Party.PartyInitData","name":"initData","type":"tuple"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","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":[{"internalType":"address","name":"","type":"address"}],"name":"isHost","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastProposalId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"votingPower","type":"uint256"},{"internalType":"address","name":"delegate","type":"address"}],"name":"mint","outputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"mintAuthority","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"mintedVotingPower","outputs":[{"internalType":"uint96","name":"","type":"uint96"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256[]","name":"","type":"uint256[]"},{"internalType":"uint256[]","name":"","type":"uint256[]"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"onERC1155BatchReceived","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"onERC1155Received","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"onERC721Received","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"owner","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"preciousListHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint40","name":"maxExecutableTime","type":"uint40"},{"internalType":"uint40","name":"cancelDelay","type":"uint40"},{"internalType":"bytes","name":"proposalData","type":"bytes"}],"internalType":"struct PartyGovernance.Proposal","name":"proposal","type":"tuple"},{"internalType":"uint256","name":"latestSnapIndex","type":"uint256"}],"name":"propose","outputs":[{"internalType":"uint256","name":"proposalId","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"royaltyInfo","outputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","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":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tokenCount","outputs":[{"internalType":"uint96","name":"","type":"uint96"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"proposalId","type":"uint256"}],"name":"veto","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"votingPowerByTokenId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]

60e06040523480156200001157600080fd5b5060405162005f5838038062005f58833981016040819052620000349162000095565b604080516020808201835260008083528351918201909352918252306080526001600160a01b03831660a052829160086200007083826200016c565b5060096200007f82826200016c565b5050506001600160a01b031660c0525062000238565b600060208284031215620000a857600080fd5b81516001600160a01b0381168114620000c057600080fd5b9392505050565b634e487b7160e01b600052604160045260246000fd5b600181811c90821680620000f257607f821691505b6020821081036200011357634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200016757600081815260208120601f850160051c81016020861015620001425750805b601f850160051c820191505b8181101562000163578281556001016200014e565b5050505b505050565b81516001600160401b03811115620001885762000188620000c7565b620001a081620001998454620000dd565b8462000119565b602080601f831160018114620001d85760008415620001bf5750858301515b600019600386901b1c1916600185901b17855562000163565b600085815260208120601f198616915b828110156200020957888601518255948401946001909101908401620001e8565b5085821015620002285787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b60805160a05160c051615c4f620003096000396000818161346a01526135430152600081816115b101528181611b4a01528181611bfc0152818161249e0152818161291901528181612a0c01528181612cc301526143540152600081816106b601528181610d72015281816111fc01528181611390015281816115140152818161168f015281816117cd01528181611a2c01528181611df001528181611fd7015281816121860152818161220c01528181612539015281816127ea015281816129b40152612d9a0152615c4f6000f3fe6080604052600436106103035760003560e01c806378cfabac11610190578063caf6aa4b116100dc578063e985e9c511610095578063f23a6e611161006f578063f23a6e6114610b19578063f3ff955a14610b46578063fa3dd61e14610b66578063fea44a5614610b935761030a565b8063e985e9c514610a9b578063eb2931b714610ad6578063f0689b4714610b065761030a565b8063caf6aa4b146109d4578063cd36324914610a01578063cf67f34414610a21578063d7faa26214610a56578063e6f26d9a14610a6c578063e8a3d48514610a865761030a565b8063a25632fd11610149578063b9fa1e9211610123578063b9fa1e9214610937578063bc197c8114610957578063c43683a114610986578063c87b56dd146109b45761030a565b8063a25632fd14610822578063b20240ee14610842578063b88d4fde146109175761030a565b806378cfabac146107665780638a415268146107865780639340b21e146107a657806395d89b41146107c65780639f181b5e146107db578063a22cb465146108025761030a565b806333b9d8c41161024f57806346904840116102085780636352211e116101e25780636352211e146106d85780636fd44cfd146106f857806370a082311461073057806374cb3041146107505761030a565b8063469048401461064757806352a702b51461066e57806356973ee5146106a45761030a565b806333b9d8c4146105925780633846b6d2146105a75780633c481576146105c75780633e4011b9146105e75780634121c9311461060757806342842e0e146106275761030a565b8063150b7a02116102bc57806324a9d8531161029657806324a9d853146104f85780632a55205a1461052b578063305a07211461056a578063314e99a21461057d5761030a565b8063150b7a02146104745780631d28dec7146104b857806323b872dd146104d85761030a565b806301ffc9a71461036157806306fdde0314610396578063081812fc146103b85780630935847914610406578063095ea7b3146104345780630d4d1513146104545761030a565b3661030a57005b34801561031657600080fd5b5061035f610322610ba8565b6000368080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610bd692505050565b005b34801561036d57600080fd5b5061038161037c366004614690565b610c9d565b60405190151581526020015b60405180910390f35b3480156103a257600080fd5b506103ab610cd8565b60405161038d91906146fd565b3480156103c457600080fd5b506103ee6103d3366004614710565b600c602052600090815260409020546001600160a01b031681565b6040516001600160a01b03909116815260200161038d565b34801561041257600080fd5b50610426610421366004614729565b610d66565b60405190815260200161038d565b34801561044057600080fd5b5061035f61044f36600461476b565b6110d0565b34801561046057600080fd5b5061042661046f366004614797565b6111b2565b34801561048057600080fd5b5061049f61048f3660046148e6565b630a85bd0160e11b949350505050565b6040516001600160e01b0319909116815260200161038d565b3480156104c457600080fd5b5061035f6104d3366004614710565b611356565b3480156104e457600080fd5b5061035f6104f3366004614951565b61150a565b34801561050457600080fd5b5060005461051890610100900461ffff1681565b60405161ffff909116815260200161038d565b34801561053757600080fd5b5061054b610546366004614729565b61157f565b604080516001600160a01b03909316835260208301919091520161038d565b61035f6105783660046149d3565b611598565b34801561058957600080fd5b5061035f611786565b34801561059e57600080fd5b506103ee61181f565b3480156105b357600080fd5b506104266105c2366004614a43565b61182e565b3480156105d357600080fd5b5061035f6105e2366004614bf2565b6118df565b3480156105f357600080fd5b5061035f610602366004614dc4565b611932565b34801561061357600080fd5b5061035f610622366004614e13565b6119ce565b34801561063357600080fd5b5061035f610642366004614951565b611de6565b34801561065357600080fd5b506000546103ee90630100000090046001600160a01b031681565b34801561067a57600080fd5b506103ee610689366004614e60565b6004602052600090815260409020546001600160a01b031681565b3480156106b057600080fd5b506103ee7f000000000000000000000000000000000000000000000000000000000000000081565b3480156106e457600080fd5b506103ee6106f3366004614710565b611e3a565b34801561070457600080fd5b50600f54610718906001600160601b031681565b6040516001600160601b03909116815260200161038d565b34801561073c57600080fd5b5061042661074b366004614e60565b611e45565b34801561075c57600080fd5b5061042660025481565b34801561077257600080fd5b50610426610781366004614710565b611ea8565b34801561079257600080fd5b506107186107a1366004614a43565b611ee9565b3480156107b257600080fd5b50600e546103ee906001600160a01b031681565b3480156107d257600080fd5b506103ab611eff565b3480156107e757600080fd5b50600e5461071890600160a01b90046001600160601b031681565b34801561080e57600080fd5b5061035f61081d366004614e8b565b611f0c565b34801561082e57600080fd5b5061042661083d366004614f3f565b611f78565b34801561084e57600080fd5b506108c7604080516080810182526000808252602082018190529181018290526060810191909152506040805160808101825260055464ffffffffff8082168352600160281b8204166020830152600160501b810461ffff1692820192909252600160601b9091046001600160601b0316606082015290565b60405161038d9190600060808201905064ffffffffff8084511683528060208501511660208401525061ffff60408401511660408301526001600160601b03606084015116606083015292915050565b34801561092357600080fd5b5061035f610932366004614f83565b61217c565b34801561094357600080fd5b5061035f610952366004614e60565b6121d2565b34801561096357600080fd5b5061049f610972366004615039565b63bc197c8160e01b98975050505050505050565b34801561099257600080fd5b506109a66109a1366004614710565b612314565b60405161038d929190615121565b3480156109c057600080fd5b506103ab6109cf366004614710565b6123bb565b3480156109e057600080fd5b506104266109ef366004614710565b60106020526000908152604090205481565b348015610a0d57600080fd5b50610718610a1c36600461517d565b6123d9565b348015610a2d57600080fd5b50610426610a3c3660046151bb565b604081018051805160208201208252606090922091905290565b348015610a6257600080fd5b5061042660015481565b348015610a7857600080fd5b506000546103819060ff1681565b348015610a9257600080fd5b506103ab612417565b348015610aa757600080fd5b50610381610ab63660046151f7565b600d60209081526000928352604080842090915290825290205460ff1681565b348015610ae257600080fd5b50610381610af1366004614e60565b60036020526000908152604090205460ff1681565b61035f610b14366004615225565b612434565b348015610b2557600080fd5b5061049f610b343660046152ea565b63f23a6e6160e01b9695505050505050565b348015610b5257600080fd5b5061035f610b61366004614e60565b6127e0565b348015610b7257600080fd5b50610b86610b81366004615372565b61286e565b60405161038d91906153a2565b348015610b9f57600080fd5b5061035f612caa565b7feb054550c406db3b89dc7016369a66aff0ce40188133281942b92e6188c6b1ef546001600160a01b031690565b604051633e4011b960e01b81523090633e4011b990610bfb9085908590600401615416565b60006040518083038186803b158015610c1357600080fd5b505afa925050508015610c24575060015b610c91573d808015610c52576040519150601f19603f3d011682016040523d82523d6000602084013e610c57565b606091505b5060008082806020019051810190610c6f919061547f565b9150915081610c8157610c8181612e10565b610c8a81612e18565b5050505050565b610c996154c5565b5050565b6000610ca882612e20565b80610cb75750610cb782612e3a565b80610cd257506001600160e01b0319821663152a902d60e11b145b92915050565b60088054610ce5906154db565b80601f0160208091040260200160405190810160405280929190818152602001828054610d11906154db565b8015610d5e5780601f10610d3357610100808354040283529160200191610d5e565b820191906000526020600020905b815481529060010190602001808311610d4157829003601f168201915b505050505081565b60006001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163003610db15760405163ea2cbbd560e01b815260040160405180910390fd5b6000838152600660209081526040808320815160a081018352815464ffffffffff8082168352600160281b8204811695830195909552600160501b8104851693820193909352600160781b83049093166060840152600160a01b9091046001600160601b0316608083015291610e2682612e7d565b90506001816007811115610e3c57610e3c6150f7565b14158015610e5c57506003816007811115610e5957610e596150f7565b14155b8015610e7a57506004816007811115610e7757610e776150f7565b14155b15610ea35780604051630821641d60e21b8152600401610e9a9190615515565b60405180910390fd5b5033600090815260028301602052604090205460ff1615610ed957604051630b517d8f60e41b8152336004820152602401610e9a565b3360008181526002840160205260408120805460ff1916600190811790915583519192610f11929091610f0b91615539565b876123d9565b90508082608001818151610f259190615557565b6001600160601b03908116909152835185546020860151604080880151606089015160808a0151909616600160a01b026001600160a01b0364ffffffffff978816600160781b0264ffffffffff60781b19938916600160501b029390931669ffffffffffffffffffff60501b19958916600160281b0269ffffffffffffffffffff1990971698909716979097179490941792909216939093171792909216919091178555517fea45672a2d92b09ff2dd48aa67615f8b5c79d7808b7282fc026a24e00283f78d915061101f908890339085909283526001600160a01b039190911660208301526001600160601b0316604082015260600190565b60405180910390a1602082015164ffffffffff16158015611069575060808201516005546110699190600160601b81046001600160601b031690600160501b900461ffff16613002565b156110ba57825469ffffffffff00000000001916600160281b4264ffffffffff160217835560405186907fe36f8b7448daff4a52e2945db0d1d7a436279cc1d527a45c27835dcbd27f336d90600090a25b50608001516001600160601b0316949350505050565b6000818152600a60205260409020546001600160a01b03163381148061111957506001600160a01b0381166000908152600d6020908152604080832033845290915290205460ff165b6111565760405162461bcd60e51b815260206004820152600e60248201526d1393d517d055551213d49256915160921b6044820152606401610e9a565b6000828152600c602052604080822080546001600160a01b0319166001600160a01b0387811691821790925591518593918516917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591a4505050565b600e546000906001600160a01b03163381146111f257604051633a33dca760e11b81523360048201526001600160a01b0382166024820152604401610e9a565b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016300361123b5760405163ea2cbbd560e01b815260040160405180910390fd5b600e54600f546005546001600160601b03600160a01b90930483169291821691600160601b90910416600061126f8861303e565b90506001600160601b0381166112858484615577565b6001600160601b031610156112a15761129e8383615577565b90505b6112ab8184615557565b92506112b8846001615557565b600e80546001600160601b03928316600160a01b81026001600160a01b0392831617909255600f80548785166bffffffffffffffffffffffff1990911617905560008281526010602090815260408083209587169095558d8316825260049052929092205490975016801561132b578097505b61133f8a6001600160601b0384168a61306f565b6113498a88613191565b5050505050509392505050565b3360009081526003602052604090205460ff1661138657604051633641391960e21b815260040160405180910390fd5b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001630036113cf5760405163ea2cbbd560e01b815260040160405180910390fd5b6000818152600660209081526040808320815160a081018352815464ffffffffff8082168352600160281b8204811695830195909552600160501b8104851693820193909352600160781b83049093166060840152600160a01b9091046001600160601b031660808301529161144482612e7d565b9050600181600781111561145a5761145a6150f7565b1415801561147a57506003816007811115611477576114776150f7565b14155b801561149857506004816007811115611495576114956150f7565b14155b156114b85780604051630821641d60e21b8152600401610e9a9190615515565b5081546001600160a01b03166001600160a01b031917825560405133815283907fc2131db10d833d6b93ae553fa450ea0f6c0c2dfb0160cb3309468bf72718f3eb9060200160405180910390a2505050565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001630036115535760405163ea2cbbd560e01b815260040160405180910390fd5b60008181526010602052604090205461156f908490849061325d565b61157a83838361328a565b505050565b60008061158a613451565b5060009050805b9250929050565b604051635c9fcd8560e11b8152600b60048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063b93f9b0a90602401602060405180830381865afa158015611600573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116249190615597565b9050336001600160a01b038216146116605760405163520b6b7560e01b81523360048201526001600160a01b0382166024820152604401610e9a565b5060005460ff1615611685576040516304e71fd360e31b815260040160405180910390fd5b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001630036116ce5760405163ea2cbbd560e01b815260040160405180910390fd5b600080856001600160a01b03168386866040516116ec9291906155b4565b60006040518083038185875af1925050503d8060008114611729576040519150601f19603f3d011682016040523d82523d6000602084013e61172e565b606091505b5091509150816117415761174181612e10565b7f66cf5924183d7d44caa75d9268a169d7c1422fef43848743d5e1ba32d5833acf8686868660405161177694939291906155ed565b60405180910390a1505050505050565b600e546001600160a01b03163381146117c357604051633a33dca760e11b81523360048201526001600160a01b0382166024820152604401610e9a565b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016300361180c5760405163ea2cbbd560e01b815260040160405180910390fd5b50600e80546001600160a01b0319169055565b6000611829610ba8565b905090565b6001600160a01b03821660009081526007602052604081208054825b818110156118bb57600060026118608484615623565b61186a919061564c565b90508564ffffffffff1684828154811061188657611886615660565b60009182526020909120015464ffffffffff1611156118a7578092506118b5565b6118b2816001615623565b91505b5061184a565b81156118d1576118cc600183615676565b6118d5565b6000195b9695505050505050565b303b8015611900576040516304a41c4d60e51b815260040160405180910390fd5b81516020808201516040808401516060808601519551948801519288015190880151610c9996949592949391906134e7565b33301461193e57600080fd5b600080836001600160a01b0316836040516119599190615689565b600060405180830381855af49150503d8060008114611994576040519150601f19603f3d011682016040523d82523d6000602084013e611999565b606091505b50915091506119c882826040516020016119b49291906156a5565b604051602081830303815290604052612e10565b50505050565b60006119d93361361f565b905080604001516001600160601b03166000148015611a03575060208101516001600160601b0316155b15611a215760405163e6de1cdd60e01b815260040160405180910390fd5b506001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163003611a6b5760405163ea2cbbd560e01b815260040160405180910390fd5b6000828152600660205260409020611a8f611a85836156c0565b82600101546136e2565b6040805160a081018252825464ffffffffff8082168352600160281b820481166020840152600160501b8204811693830193909352600160781b81049092166060820152600160a01b9091046001600160601b031660808201526000611af482612e7d565b90506005816007811115611b0a57611b0a6150f7565b14611b2a5780604051630821641d60e21b8152600401610e9a9190615515565b506000611b3d60408501602086016156cc565b64ffffffffff16905060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663441abbac600f6040518263ffffffff1660e01b8152600401611b9791815260200190565b602060405180830381865afa158015611bb4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bd891906156e7565b604051631106aeeb60e21b8152601760048201529091506000906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063441abbac90602401602060405180830381865afa158015611c43573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c6791906156e7565b90508115611c7b5781831115611c7b578192505b8015611c8d5780831015611c8d578092505b600083856040015164ffffffffff16611ca69190615623565b905080421015611cda576040516303861c4b60e41b815264ffffffffff428116600483015282166024820152604401610e9a565b5050835464ffffffffff60781b1916600160781b648000000000421764ffffffffff1602178455506000905080611d0f610ba8565b6001600160a01b031686604051602401611d2b91815260200190565b60408051601f198184030181529181526020820180516001600160e01b031663e0a8f6f560e01b17905251611d609190615689565b600060405180830381855af49150503d8060008114611d9b576040519150601f19603f3d011682016040523d82523d6000602084013e611da0565b606091505b509150915081611db357611db381612e10565b505060405184907f416e669c63d9a3a5e36ee7cc7e2104b8db28ccd286aa18966e98fa230c73b08c90600090a250505050565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163003611e2f5760405163ea2cbbd560e01b815260040160405180910390fd5b61157a838383613721565b6000610cd2826137f1565b60006001600160a01b038216611e8c5760405162461bcd60e51b815260206004820152600c60248201526b5a45524f5f4144445245535360a01b6044820152606401610e9a565b506001600160a01b03166000908152600b602052604090205490565b600554600090600160601b90046001600160601b0316600083815260106020526040902054611edf90670de0b6b3a7640000615700565b610cd2919061564c565b6000611ef883836000196123d9565b9392505050565b60098054610ce5906154db565b336000818152600d602090815260408083206001600160a01b03871680855290835292819020805460ff191686151590811790915590519081529192917f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a35050565b600080611f843361361f565b905080604001516001600160601b03166000148015611fae575060208101516001600160601b0316155b15611fcc5760405163e6de1cdd60e01b815260040160405180910390fd5b506001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001630036120165760405163ea2cbbd560e01b815260040160405180910390fd5b60026000815461202590615717565b91829055506040805160a08101825264ffffffffff4216815260006020820181905291810182905260608101829052608081019190915290915061207d84604081018051805160208201208252606090922091905290565b600083815260066020908152604091829020600181019390935583518354918501518584015160608701516080909701516001600160601b0316600160a01b026001600160a01b0364ffffffffff988916600160781b0264ffffffffff60781b19938a16600160501b029390931669ffffffffffffffffffff60501b19948a16600160281b0269ffffffffffffffffffff1990971699909516989098179490941791909116919091171793909316929092179055517fea77d064c7d953e57748855e7b0751ea190d1df7505615a4e39336d4d548f6889061216390839033908790615730565b60405180910390a16121758183610d66565b5092915050565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001630036121c55760405163ea2cbbd560e01b815260040160405180910390fd5b610c8a8585858585613848565b3360009081526003602052604090205460ff1661220257604051633641391960e21b815260040160405180910390fd5b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016300361224b5760405163ea2cbbd560e01b815260040160405180910390fd5b6001600160a01b038116156122b8576001600160a01b03811660009081526003602052604090205460ff16156122945760405163640c1a3360e01b815260040160405180910390fd5b6001600160a01b0381166000908152600360205260409020805460ff191660011790555b33600081815260036020908152604091829020805460ff1916905581519283526001600160a01b038416908301527fddffcdb3bb07c5efc18b0918cf4e3e88c7d42cc05156cdadb2ec12c3b5ff892f910160405180910390a150565b6040805160a081018252600080825260208201819052918101829052606081018290526080810182905250600082815260066020908152604091829020825160a081018452905464ffffffffff8082168352600160281b8204811693830193909352600160501b8104831693820193909352600160781b83049091166060820152600160a01b9091046001600160601b031660808201526123b481612e7d565b9150915091565b60606123c5613451565b505060408051602081019091526000815290565b6000806123e7858585613906565b905080602001518160600151612401578160400151612404565b60005b61240e9190615557565b95945050505050565b6060612421613451565b5060408051602081019091526000815290565b600061243f3361361f565b905080604001516001600160601b03166000148015612469575060208101516001600160601b0316155b156124875760405163e6de1cdd60e01b815260040160405180910390fd5b506040516331a1aa3360e11b8152601560048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690636343546690602401602060405180830381865afa1580156124ed573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612511919061577f565b1561252f57604051632fb3e88560e01b815260040160405180910390fd5b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001630036125785760405163ea2cbbd560e01b815260040160405180910390fd5b600088815260066020526040902060018101546125969089906136e2565b6040805160a081018252825464ffffffffff8082168352600160281b820481166020840152600160501b8204811693830193909352600160781b81049092166060820152600160a01b9091046001600160601b0316608082015260006125fb82612e7d565b90506004816007811115612611576126116150f7565b141580156126315750600581600781111561262e5761262e6150f7565b14155b156126515780604051630821641d60e21b8152600401610e9a9190615515565b6004816007811115612665576126656150f7565b036126ca57428a6000015164ffffffffff1610156126ab578951604051632f7e600560e21b815264ffffffffff9182166004820152429091166024820152604401610e9a565b825464ffffffffff60501b1916600160501b4264ffffffffff16021783555b88516020908102818b0120600090815289518202828b0120909152604090206001541461270a57604051633b43666f60e01b815260040160405180910390fd5b825464ffffffffff60781b1916600160781b4264ffffffffff160217835560006127bb8c8c8c8c61273a88613a81565b8d8d8080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050508c8c8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250613aba92505050565b9050806127d257835464ffffffffff60781b191684555b505050505050505050505050565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001630036128295760405163ea2cbbd560e01b815260040160405180910390fd5b6128353360008361306f565b6040516001600160a01b0382169033907fbfa9be947969a7d4f47eceedb207379702a5e9e8b82ec09d564da75195f8689e90600090a350565b6040805160e081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c08101919091523330146129035760006128b93361361f565b905080604001516001600160601b031660001480156128e3575060208101516001600160601b0316155b156129015760405163e6de1cdd60e01b815260040160405180910390fd5b505b6040516331a1aa3360e11b8152601560048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690636343546690602401602060405180830381865afa158015612968573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061298c919061577f565b156129aa57604051632fb3e88560e01b815260040160405180910390fd5b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001630036129f35760405163ea2cbbd560e01b815260040160405180910390fd5b604051635c9fcd8560e11b8152600c60048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063b93f9b0a90602401602060405180830381865afa158015612a5b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a7f9190615597565b90507fdda962f630bf2f85c8412f305206a4f363688481dd632689f88ad7022e4cc233858585604051612ab49392919061579c565b60405180910390a160008054630100000081046001600160a01b03169161010090910461ffff1690876001811115612aee57612aee6150f7565b03612b7b57604051631d1972a760e11b81523060048201526001600160a01b03838116602483015261ffff83166044830152841690633a32e54e90479060640160e06040518083038185885af1158015612b4c573d6000803e3d6000fd5b50505050506040513d601f19601f82011682018060405250810190612b7191906157db565b9350505050611ef8565b6001876001811115612b8f57612b8f6150f7565b14612b9c57612b9c6154c5565b6040516370a0823160e01b8152306004820152612c1b9084906001600160a01b038916906370a0823190602401602060405180830381865afa158015612be6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c0a91906156e7565b6001600160a01b0389169190613c06565b60405163eedaf00d60e01b81526001600160a01b038781166004830152306024830152838116604483015261ffff8316606483015284169063eedaf00d9060840160e0604051808303816000875af1158015612c7b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c9f91906157db565b979650505050505050565b604051635c9fcd8560e11b8152600b60048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063b93f9b0a90602401602060405180830381865afa158015612d12573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d369190615597565b9050336001600160a01b03821614801590612d6157503360009081526003602052604090205460ff16155b15612d905760405163e670248160e01b81523360048201526001600160a01b0382166024820152604401610e9a565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163003612dd95760405163ea2cbbd560e01b815260040160405180910390fd5b6000805460ff191660011781556040517f447e75484d6bdb571b4a92ae14018db7b6dd41f3f02360690c554e1d48f46f879190a150565b805160208201fd5b805160208201f35b6000612e2b82613d38565b80610cd25750610cd282613d6e565b6000612e4582612e20565b80612e6057506380ac58cd60e01b6001600160e01b03198316145b80610cd25750506001600160e01b031916635b5e139f60e01b1490565b805160009064ffffffffff168103612e9757506000919050565b604082015164ffffffffff1615612eec57816060015164ffffffffff16600003612ec357506005919050565b64800000000080836060015164ffffffffff161603612ee457506007919050565b506006919050565b6001600160601b03801682608001516001600160601b031603612f1157506002919050565b6040805160808101825260055464ffffffffff8082168352600160281b82048116602080850191909152600160501b830461ffff1694840194909452600160601b9091046001600160601b031660608301529184015142921615612fcc578164ffffffffff1681602001518560200151612f8b919061588b565b64ffffffffff1611612fa1575060049392505050565b612fb384608001518260600151613d99565b15612fc2575060049392505050565b5060039392505050565b8051845164ffffffffff841691612fe29161588b565b64ffffffffff1611612ff8575060029392505050565b5060019392505050565b60008161ffff16836001600160601b0316856001600160601b031661271061302a9190615700565b613034919061564c565b1015949350505050565b60006001600160601b0382111561306b57604051636f55e21560e11b815260048101839052602401610e9a565b5090565b600061307a8461361f565b6001600160a01b038086166000908152600460205260409020549192501680156130a457806130a6565b845b90506001600160a01b038316156130bd57826130bf565b805b9250600060405180608001604052804264ffffffffff16815260200184602001516001600160601b031681526020016131218761310f87604001516001600160601b03166001600160601b031690565b61311991906158a9565b60170b613dcc565b6001600160601b031681526001600160a01b038681169089161415602090910152905061314e8682613e0d565b6001600160a01b03868116600090815260046020526040902080546001600160a01b0319169186169190911790556131898683868685613fe6565b505050505050565b61319b8282614194565b6001600160a01b0382163b15806132415750604051630a85bd0160e11b80825233600483015260006024830181905260448301849052608060648401526084830152906001600160a01b0384169063150b7a029060a4016020604051808303816000875af1158015613211573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061323591906158d6565b6001600160e01b031916145b610c995760405162461bcd60e51b8152600401610e9a906158f3565b60006132688261429f565b905061327e846132778361591d565b600061306f565b6119c88382600061306f565b6000818152600a60205260409020546001600160a01b038481169116146132e05760405162461bcd60e51b815260206004820152600a60248201526957524f4e475f46524f4d60b01b6044820152606401610e9a565b6001600160a01b03821661332a5760405162461bcd60e51b81526020600482015260116024820152701253959053125117d49150d25412515395607a1b6044820152606401610e9a565b336001600160a01b038416148061336457506001600160a01b0383166000908152600d6020908152604080832033845290915290205460ff165b8061338557506000818152600c60205260409020546001600160a01b031633145b6133c25760405162461bcd60e51b815260206004820152600e60248201526d1393d517d055551213d49256915160921b6044820152606401610e9a565b6001600160a01b038084166000818152600b60209081526040808320805460001901905593861680835284832080546001019055858352600a825284832080546001600160a01b03199081168317909155600c90925284832080549092169091559251849392917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4505050565b604051635c9fcd8560e11b81526004808201526134dd907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063b93f9b0a90602401602060405180830381865afa1580156134b9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103229190615597565b6134e56154c5565b565b6134f28484846142cc565b60086134fe8882615986565b50600961350b8782615986565b50600e80546001600160a01b0319166001600160a01b038316179055841561361657604051635c9fcd8560e11b8152601660048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063b93f9b0a90602401602060405180830381865afa158015613592573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135b69190615597565b6001600160a01b031663fc9968df866040518263ffffffff1660e01b81526004016135e391815260200190565b600060405180830381600087803b1580156135fd57600080fd5b505af1158015613611573d6000803e3d6000fd5b505050505b50505050505050565b6040805160808101825260008082526020808301829052828401829052606083018290526001600160a01b03851682526007905291909120805480156136db578161366b600183615676565b8154811061367b5761367b615660565b600091825260209182902060408051608081018252929091015464ffffffffff81168352600160281b81046001600160601b0390811694840194909452600160881b810490931690820152600160e81b90910460ff161515606082015292505b5050919050565b60408201805180516020820120825260608420915280821461157a57604051630267877160e11b81526004810182905260248101839052604401610e9a565b61372c83838361150a565b6001600160a01b0382163b15806137d55750604051630a85bd0160e11b8082523360048301526001600160a01b03858116602484015260448301849052608060648401526000608484015290919084169063150b7a029060a4016020604051808303816000875af11580156137a5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137c991906158d6565b6001600160e01b031916145b61157a5760405162461bcd60e51b8152600401610e9a906158f3565b6000818152600a60205260409020546001600160a01b0316806138435760405162461bcd60e51b815260206004820152600a6024820152691393d517d3525395115160b21b6044820152606401610e9a565b919050565b61385385858561150a565b6001600160a01b0384163b15806138ea5750604051630a85bd0160e11b808252906001600160a01b0386169063150b7a029061389b9033908a90899089908990600401615a45565b6020604051808303816000875af11580156138ba573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138de91906158d6565b6001600160e01b031916145b610c8a5760405162461bcd60e51b8152600401610e9a906158f3565b6040805160808101825260008082526020808301829052828401829052606083018290526001600160a01b0387168252600790529190912080548015613a7857808410801561398057508464ffffffffff1682858154811061396a5761396a615660565b60009182526020909120015464ffffffffff1611155b80156139d35750613992600182615676565b8414806139d3575064ffffffffff8516826139ae866001615623565b815481106139be576139be615660565b60009182526020909120015464ffffffffff16115b15613a51578184815481106139ea576139ea615660565b600091825260209182902060408051608081018252929091015464ffffffffff81168352600160281b81046001600160601b0390811694840194909452600160881b810490931690820152600160e81b90910460ff16151560608201529250611ef8915050565b613a5b868661182e565b93506000198414613a78578184815481106139ea576139ea615660565b50509392505050565b6080810151600554600091613aa591600160601b90046001600160601b0316613d99565b15613ab257506001919050565b506000919050565b6000806040518060e001604052808a8152602001896040015181526020018581526020018481526020018681526020018881526020018781525090506060600080613b03610ba8565b6001600160a01b031684604051602401613b1d9190615ab4565b60408051601f198184030181529181526020820180516001600160e01b031663a7c8a3f960e01b17905251613b529190615689565b600060405180830381855af49150503d8060008114613b8d576040519150601f19603f3d011682016040523d82523d6000602084013e613b92565b606091505b509150915081613ba557613ba581612e10565b80806020019051810190613bb99190615b94565b92505050897fc98fbf8f20b11b050a9541d12aee1c11fcd31e8e42975cc885fb3d33a6accc823383604051613bef929190615416565b60405180910390a251159998505050505050505050565b6040516001600160a01b03838116602483015260448201839052600091829186169060640160408051601f198184030181529181526020820180516001600160e01b031663a9059cbb60e01b17905251613c609190615689565b6000604051808303816000865af19150503d8060008114613c9d576040519150601f19603f3d011682016040523d82523d6000602084013e613ca2565b606091505b50915091508115613d05578051600003613ce557843b600081900361318957604051639fe23a3960e01b81526001600160a01b0387166004820152602401610e9a565b80806020019051810190613cf9919061577f565b15613d05575050505050565b604051631702a98760e11b81526001600160a01b0380871660048301528516602482015260448101849052606401610e9a565b60006301ffc9a760e01b6001600160e01b031983161480610cd257506001600160e01b03198216630a85bd0160e11b1492915050565b6000613d7982613d38565b80610cd257506001600160e01b03198216630271189760e51b1492915050565b60008082613da985612710615bc8565b613db39190615bf3565b61270f6001600160601b03919091161015949350505050565b6000808260170b1280613de957506001600160601b03601783900b135b1561306b576040516394e08f6160e01b8152601783900b6004820152602401610e9a565b6001600160a01b038216600090815260076020526040902080548015613f5c57600082613e3b600184615676565b81548110613e4b57613e4b615660565b600091825260209182902060408051608081018252919092015464ffffffffff8082168084526001600160601b03600160281b8404811696850196909652600160881b83049095169383019390935260ff600160e81b90910416151560608201528651909350169003613f5a578383613ec5600185615676565b81548110613ed557613ed5615660565b60009182526020918290208351910180549284015160408501516060909501511515600160e81b0260ff60e81b196001600160601b03968716600160881b0216600160881b600160f01b031996909216600160281b026001600160881b031990951664ffffffffff909416939093179390931793909316919091171790555050505050565b505b50805460018101825560009182526020918290208351910180549284015160408501516060909501511515600160e81b0260ff60e81b196001600160601b03968716600160881b0216600160881b600160f01b031996909216600160281b026001600160881b031990951664ffffffffff9094169390931793909317939093169190911717905550565b6001600160a01b038316158061400357506001600160a01b038416155b156140215760405163e5ec2d2560e01b815260040160405180910390fd5b846001600160a01b0316846001600160a01b0316141580156140555750826001600160a01b0316846001600160a01b031614155b156140cf5760006140658561361f565b9050600060405180608001604052804264ffffffffff168152602001856040015184602001516140959190615577565b6001600160601b0316815260200183604001516001600160601b031681526020018360600151151581525090506140cc8682613e0d565b50505b846001600160a01b0316836001600160a01b031614610c8a5760006140f38461361f565b905060008260400151826020015161410b9190615557565b9050856001600160a01b0316856001600160a01b0316036141385760408401516141359082615577565b90505b600060405180608001604052804264ffffffffff168152602001836001600160601b0316815260200184604001516001600160601b0316815260200184606001511515815250905061418a8682613e0d565b5050505050505050565b6001600160a01b0382166141de5760405162461bcd60e51b81526020600482015260116024820152701253959053125117d49150d25412515395607a1b6044820152606401610e9a565b6000818152600a60205260409020546001600160a01b0316156142345760405162461bcd60e51b815260206004820152600e60248201526d1053149150511657d3525395115160921b6044820152606401610e9a565b6001600160a01b0382166000818152600b6020908152604080832080546001019055848352600a90915280822080546001600160a01b0319168417905551839291907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a45050565b60006001600160bf1b0382111561306b5760405163e9a5989b60e01b815260048101839052602401610e9a565b6127108360a0015161ffff1611156143035760a08301516040516323dd0d6d60e11b815261ffff9091166004820152602401610e9a565b612710836060015161ffff16111561433a5760608301516040516323dd0d6d60e11b815261ffff9091166004820152602401610e9a565b604051635c9fcd8560e11b8152600260048201526143dc907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063b93f9b0a90602401602060405180830381865afa1580156143a3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906143c79190615597565b6040518060200160405280600081525061454e565b604080516080808201835260208681015164ffffffffff9081168085528886015190911691840182905260608089015161ffff908116968601879052938901516001600160601b031694018490526005805469ffffffffffffffffffff1916909117600160281b909202919091176dffffffffffffffffffffffffffff60501b1916600160501b9094026bffffffffffffffffffffffff60601b191693909317600160601b9092029190911790915560a08401516000805460c0870151610100600160b81b031990911661010093909416929092026301000000600160b81b0319169290921763010000006001600160a01b03909216919091021790556144e3828261462f565b60005b8351518110156119c8576001600360008660000151848151811061450c5761450c615660565b6020908102919091018101516001600160a01b03168252810191909152604001600020805460ff191691151591909117905561454781615717565b90506144e6565b7feb054550c406db3b89dc7016369a66aff0ce40188133281942b92e6188c6b1ef80546001600160a01b031981166001600160a01b03858116918217845560405192169160009182916145a79085908890602401615416565b60408051601f198184030181529181526020820180516001600160e01b031663347d5e2560e21b179052516145dc9190615689565b600060405180830381855af49150503d8060008114614617576040519150601f19603f3d011682016040523d82523d6000602084013e61461c565b606091505b5091509150816131895761318981612e10565b8051825114614651576040516357cc2fc760e01b815260040160405180910390fd5b815160209081028184012060009081528251820282840120909152604090206001555050565b6001600160e01b03198116811461468d57600080fd5b50565b6000602082840312156146a257600080fd5b8135611ef881614677565b60005b838110156146c85781810151838201526020016146b0565b50506000910152565b600081518084526146e98160208601602086016146ad565b601f01601f19169290920160200192915050565b602081526000611ef860208301846146d1565b60006020828403121561472257600080fd5b5035919050565b6000806040838503121561473c57600080fd5b50508035926020909101359150565b6001600160a01b038116811461468d57600080fd5b80356138438161474b565b6000806040838503121561477e57600080fd5b82356147898161474b565b946020939093013593505050565b6000806000606084860312156147ac57600080fd5b83356147b78161474b565b92506020840135915060408401356147ce8161474b565b809150509250925092565b634e487b7160e01b600052604160045260246000fd5b604051608081016001600160401b0381118282101715614811576148116147d9565b60405290565b60405160e081016001600160401b0381118282101715614811576148116147d9565b604051601f8201601f191681016001600160401b0381118282101715614861576148616147d9565b604052919050565b60006001600160401b03821115614882576148826147d9565b50601f01601f191660200190565b600082601f8301126148a157600080fd5b81356148b46148af82614869565b614839565b8181528460208386010111156148c957600080fd5b816020850160208301376000918101602001919091529392505050565b600080600080608085870312156148fc57600080fd5b84356149078161474b565b935060208501356149178161474b565b92506040850135915060608501356001600160401b0381111561493957600080fd5b61494587828801614890565b91505092959194509250565b60008060006060848603121561496657600080fd5b83356149718161474b565b925060208401356149818161474b565b929592945050506040919091013590565b60008083601f8401126149a457600080fd5b5081356001600160401b038111156149bb57600080fd5b60208301915083602082850101111561159157600080fd5b600080600080606085870312156149e957600080fd5b84356149f48161474b565b935060208501356001600160401b03811115614a0f57600080fd5b614a1b87828801614992565b9598909750949560400135949350505050565b803564ffffffffff8116811461384357600080fd5b60008060408385031215614a5657600080fd5b8235614a618161474b565b9150614a6f60208401614a2e565b90509250929050565b60006001600160401b03821115614a9157614a916147d9565b5060051b60200190565b600082601f830112614aac57600080fd5b81356020614abc6148af83614a78565b82815260059290921b84018101918181019086841115614adb57600080fd5b8286015b84811015614aff578035614af28161474b565b8352918301918301614adf565b509695505050505050565b803561ffff8116811461384357600080fd5b80356001600160601b038116811461384357600080fd5b600082601f830112614b4457600080fd5b81356020614b546148af83614a78565b82815260059290921b84018101918181019086841115614b7357600080fd5b8286015b84811015614aff578035614b8a8161474b565b8352918301918301614b77565b600082601f830112614ba857600080fd5b81356020614bb86148af83614a78565b82815260059290921b84018101918181019086841115614bd757600080fd5b8286015b84811015614aff5780358352918301918301614bdb565b60006020808385031215614c0557600080fd5b82356001600160401b0380821115614c1c57600080fd5b9084019060808287031215614c3057600080fd5b614c386147ef565b823582811115614c4757600080fd5b830160808189031215614c5957600080fd5b614c616147ef565b813584811115614c7057600080fd5b820160e0818b031215614c8257600080fd5b614c8a614817565b813586811115614c9957600080fd5b614ca58c828501614a9b565b825250614cb3888301614a2e565b888201526040614cc4818401614a2e565b818301526060614cd5818501614b0a565b81840152614ce560808501614b1c565b6080840152614cf660a08501614b0a565b60a0840152614d0760c08501614760565b60c084015282855289860135935087841115614d2257600080fd5b614d2e8d858801614890565b8a86015281860135935087841115614d4557600080fd5b614d518d858801614890565b858301529485013585850152838652878901359487861115614d7257600080fd5b614d7e8d878b01614b33565b8a880152818901359950878a1115614d9557600080fd5b614da18d8b8b01614b97565b82880152614db0818a01614760565b9087015250939a9950505050505050505050565b60008060408385031215614dd757600080fd5b8235614de28161474b565b915060208301356001600160401b03811115614dfd57600080fd5b614e0985828601614890565b9150509250929050565b60008060408385031215614e2657600080fd5b8235915060208301356001600160401b03811115614e4357600080fd5b830160608186031215614e5557600080fd5b809150509250929050565b600060208284031215614e7257600080fd5b8135611ef88161474b565b801515811461468d57600080fd5b60008060408385031215614e9e57600080fd5b8235614ea98161474b565b91506020830135614e5581614e7d565b600060608284031215614ecb57600080fd5b604051606081016001600160401b038282108183111715614eee57614eee6147d9565b81604052829350614efe85614a2e565b8352614f0c60208601614a2e565b60208401526040850135915080821115614f2557600080fd5b50614f3285828601614890565b6040830152505092915050565b60008060408385031215614f5257600080fd5b82356001600160401b03811115614f6857600080fd5b614f7485828601614eb9565b95602094909401359450505050565b600080600080600060808688031215614f9b57600080fd5b8535614fa68161474b565b94506020860135614fb68161474b565b93506040860135925060608601356001600160401b03811115614fd857600080fd5b614fe488828901614992565b969995985093965092949392505050565b60008083601f84011261500757600080fd5b5081356001600160401b0381111561501e57600080fd5b6020830191508360208260051b850101111561159157600080fd5b60008060008060008060008060a0898b03121561505557600080fd5b88356150608161474b565b975060208901356150708161474b565b965060408901356001600160401b038082111561508c57600080fd5b6150988c838d01614ff5565b909850965060608b01359150808211156150b157600080fd5b6150bd8c838d01614ff5565b909650945060808b01359150808211156150d657600080fd5b506150e38b828c01614992565b999c989b5096995094979396929594505050565b634e487b7160e01b600052602160045260246000fd5b6008811061511d5761511d6150f7565b9052565b60c0810161512f828561510d565b64ffffffffff808451166020840152806020850151166040840152806040850151166060840152806060850151166080840152506001600160601b0360808401511660a08301529392505050565b60008060006060848603121561519257600080fd5b833561519d8161474b565b92506151ab60208501614a2e565b9150604084013590509250925092565b6000602082840312156151cd57600080fd5b81356001600160401b038111156151e357600080fd5b6151ef84828501614eb9565b949350505050565b6000806040838503121561520a57600080fd5b82356152158161474b565b91506020830135614e558161474b565b60008060008060008060008060c0898b03121561524157600080fd5b8835975060208901356001600160401b038082111561525f57600080fd5b61526b8c838d01614eb9565b985060408b013591508082111561528157600080fd5b61528d8c838d01614b33565b975060608b01359150808211156152a357600080fd5b6152af8c838d01614b97565b965060808b01359150808211156152c557600080fd5b6152d18c838d01614992565b909650945060a08b01359150808211156150d657600080fd5b60008060008060008060a0878903121561530357600080fd5b863561530e8161474b565b9550602087013561531e8161474b565b9450604087013593506060870135925060808701356001600160401b0381111561534757600080fd5b61535389828a01614992565b979a9699509497509295939492505050565b6002811061468d57600080fd5b60008060006060848603121561538757600080fd5b833561497181615365565b6002811061511d5761511d6150f7565b600060e0820190506153b5828451615392565b60208301516020830152604083015160018060a01b038082166040850152806060860151166060850152806080860151166080850152505060a08301516001600160801b0380821660a08501528060c08601511660c0850152505092915050565b6001600160a01b03831681526040602082018190526000906151ef908301846146d1565b600082601f83011261544b57600080fd5b81516154596148af82614869565b81815284602083860101111561546e57600080fd5b6151ef8260208301602087016146ad565b6000806040838503121561549257600080fd5b825161549d81614e7d565b60208401519092506001600160401b038111156154b957600080fd5b614e098582860161543a565b634e487b7160e01b600052600160045260246000fd5b600181811c908216806154ef57607f821691505b60208210810361550f57634e487b7160e01b600052602260045260246000fd5b50919050565b60208101610cd2828461510d565b634e487b7160e01b600052601160045260246000fd5b64ffffffffff82811682821603908082111561217557612175615523565b6001600160601b0381811683821601908082111561217557612175615523565b6001600160601b0382811682821603908082111561217557612175615523565b6000602082840312156155a957600080fd5b8151611ef88161474b565b8183823760009101908152919050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b6001600160a01b038516815260606020820181905260009061561290830185876155c4565b905082604083015295945050505050565b80820180821115610cd257610cd2615523565b634e487b7160e01b600052601260045260246000fd5b60008261565b5761565b615636565b500490565b634e487b7160e01b600052603260045260246000fd5b81810381811115610cd257610cd2615523565b6000825161569b8184602087016146ad565b9190910192915050565b82151581526040602082015260006151ef60408301846146d1565b6000610cd23683614eb9565b6000602082840312156156de57600080fd5b611ef882614a2e565b6000602082840312156156f957600080fd5b5051919050565b8082028115828204841417610cd257610cd2615523565b60006001820161572957615729615523565b5060010190565b83815260018060a01b038316602082015260606040820152600064ffffffffff808451166060840152806020850151166080840152506040830151606060a08401526118d560c08401826146d1565b60006020828403121561579157600080fd5b8151611ef881614e7d565b606081016157aa8286615392565b6001600160a01b0393909316602082015260400152919050565b80516001600160801b038116811461384357600080fd5b600060e082840312156157ed57600080fd5b60405160e081018181106001600160401b038211171561580f5761580f6147d9565b604052825161581d81615365565b81526020838101519082015260408301516158378161474b565b6040820152606083015161584a8161474b565b6060820152608083015161585d8161474b565b608082015261586e60a084016157c4565b60a082015261587f60c084016157c4565b60c08201529392505050565b64ffffffffff81811683821601908082111561217557612175615523565b601781810b9083900b016001600160bf1b0381136001600160bf1b031982121715610cd257610cd2615523565b6000602082840312156158e857600080fd5b8151611ef881614677565b60208082526010908201526f155394d0519157d49150d2541251539560821b604082015260600190565b6000601782900b600160bf1b810161593757615937615523565b60000392915050565b601f82111561157a57600081815260208120601f850160051c810160208610156159675750805b601f850160051c820191505b8181101561318957828155600101615973565b81516001600160401b0381111561599f5761599f6147d9565b6159b3816159ad84546154db565b84615940565b602080601f8311600181146159e857600084156159d05750858301515b600019600386901b1c1916600185901b178555613189565b600085815260208120601f198616915b82811015615a17578886015182559484019460019091019084016159f8565b5085821015615a355787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6001600160a01b0386811682528516602082015260408101849052608060608201819052600090612c9f90830184866155c4565b600081518084526020808501945080840160005b83811015615aa957815187529582019590820190600101615a8d565b509495945050505050565b600060208083528351818401528084015160e06040850152615ada6101008501826146d1565b90506040850151601f1980868403016060870152615af883836146d1565b92506060870151915080868403016080870152615b1583836146d1565b608088015160a088810191909152880151878203830160c08901528051808352908601945060009350908501905b80841015615b6c5784516001600160a01b03168252938501936001939093019290850190615b43565b5060c08801519450818782030160e0880152615b888186615a79565b98975050505050505050565b600060208284031215615ba657600080fd5b81516001600160401b03811115615bbc57600080fd5b6151ef8482850161543a565b6001600160601b03818116838216028082169190828114615beb57615beb615523565b505092915050565b60006001600160601b0380841680615c0d57615c0d615636565b9216919091049291505056fea26469706673582212200be9ace9cf91e260ff128ec1313e3ba1d8ac3af33e7e0d741297e426349a86d664736f6c634300081100330000000000000000000000001ca20040ce6ad406bc2a6c89976388829e7fbade

Deployed Bytecode

0x6080604052600436106103035760003560e01c806378cfabac11610190578063caf6aa4b116100dc578063e985e9c511610095578063f23a6e611161006f578063f23a6e6114610b19578063f3ff955a14610b46578063fa3dd61e14610b66578063fea44a5614610b935761030a565b8063e985e9c514610a9b578063eb2931b714610ad6578063f0689b4714610b065761030a565b8063caf6aa4b146109d4578063cd36324914610a01578063cf67f34414610a21578063d7faa26214610a56578063e6f26d9a14610a6c578063e8a3d48514610a865761030a565b8063a25632fd11610149578063b9fa1e9211610123578063b9fa1e9214610937578063bc197c8114610957578063c43683a114610986578063c87b56dd146109b45761030a565b8063a25632fd14610822578063b20240ee14610842578063b88d4fde146109175761030a565b806378cfabac146107665780638a415268146107865780639340b21e146107a657806395d89b41146107c65780639f181b5e146107db578063a22cb465146108025761030a565b806333b9d8c41161024f57806346904840116102085780636352211e116101e25780636352211e146106d85780636fd44cfd146106f857806370a082311461073057806374cb3041146107505761030a565b8063469048401461064757806352a702b51461066e57806356973ee5146106a45761030a565b806333b9d8c4146105925780633846b6d2146105a75780633c481576146105c75780633e4011b9146105e75780634121c9311461060757806342842e0e146106275761030a565b8063150b7a02116102bc57806324a9d8531161029657806324a9d853146104f85780632a55205a1461052b578063305a07211461056a578063314e99a21461057d5761030a565b8063150b7a02146104745780631d28dec7146104b857806323b872dd146104d85761030a565b806301ffc9a71461036157806306fdde0314610396578063081812fc146103b85780630935847914610406578063095ea7b3146104345780630d4d1513146104545761030a565b3661030a57005b34801561031657600080fd5b5061035f610322610ba8565b6000368080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610bd692505050565b005b34801561036d57600080fd5b5061038161037c366004614690565b610c9d565b60405190151581526020015b60405180910390f35b3480156103a257600080fd5b506103ab610cd8565b60405161038d91906146fd565b3480156103c457600080fd5b506103ee6103d3366004614710565b600c602052600090815260409020546001600160a01b031681565b6040516001600160a01b03909116815260200161038d565b34801561041257600080fd5b50610426610421366004614729565b610d66565b60405190815260200161038d565b34801561044057600080fd5b5061035f61044f36600461476b565b6110d0565b34801561046057600080fd5b5061042661046f366004614797565b6111b2565b34801561048057600080fd5b5061049f61048f3660046148e6565b630a85bd0160e11b949350505050565b6040516001600160e01b0319909116815260200161038d565b3480156104c457600080fd5b5061035f6104d3366004614710565b611356565b3480156104e457600080fd5b5061035f6104f3366004614951565b61150a565b34801561050457600080fd5b5060005461051890610100900461ffff1681565b60405161ffff909116815260200161038d565b34801561053757600080fd5b5061054b610546366004614729565b61157f565b604080516001600160a01b03909316835260208301919091520161038d565b61035f6105783660046149d3565b611598565b34801561058957600080fd5b5061035f611786565b34801561059e57600080fd5b506103ee61181f565b3480156105b357600080fd5b506104266105c2366004614a43565b61182e565b3480156105d357600080fd5b5061035f6105e2366004614bf2565b6118df565b3480156105f357600080fd5b5061035f610602366004614dc4565b611932565b34801561061357600080fd5b5061035f610622366004614e13565b6119ce565b34801561063357600080fd5b5061035f610642366004614951565b611de6565b34801561065357600080fd5b506000546103ee90630100000090046001600160a01b031681565b34801561067a57600080fd5b506103ee610689366004614e60565b6004602052600090815260409020546001600160a01b031681565b3480156106b057600080fd5b506103ee7f00000000000000000000000052010e220e5c8ef2217d86cfa58da51da39e8ec481565b3480156106e457600080fd5b506103ee6106f3366004614710565b611e3a565b34801561070457600080fd5b50600f54610718906001600160601b031681565b6040516001600160601b03909116815260200161038d565b34801561073c57600080fd5b5061042661074b366004614e60565b611e45565b34801561075c57600080fd5b5061042660025481565b34801561077257600080fd5b50610426610781366004614710565b611ea8565b34801561079257600080fd5b506107186107a1366004614a43565b611ee9565b3480156107b257600080fd5b50600e546103ee906001600160a01b031681565b3480156107d257600080fd5b506103ab611eff565b3480156107e757600080fd5b50600e5461071890600160a01b90046001600160601b031681565b34801561080e57600080fd5b5061035f61081d366004614e8b565b611f0c565b34801561082e57600080fd5b5061042661083d366004614f3f565b611f78565b34801561084e57600080fd5b506108c7604080516080810182526000808252602082018190529181018290526060810191909152506040805160808101825260055464ffffffffff8082168352600160281b8204166020830152600160501b810461ffff1692820192909252600160601b9091046001600160601b0316606082015290565b60405161038d9190600060808201905064ffffffffff8084511683528060208501511660208401525061ffff60408401511660408301526001600160601b03606084015116606083015292915050565b34801561092357600080fd5b5061035f610932366004614f83565b61217c565b34801561094357600080fd5b5061035f610952366004614e60565b6121d2565b34801561096357600080fd5b5061049f610972366004615039565b63bc197c8160e01b98975050505050505050565b34801561099257600080fd5b506109a66109a1366004614710565b612314565b60405161038d929190615121565b3480156109c057600080fd5b506103ab6109cf366004614710565b6123bb565b3480156109e057600080fd5b506104266109ef366004614710565b60106020526000908152604090205481565b348015610a0d57600080fd5b50610718610a1c36600461517d565b6123d9565b348015610a2d57600080fd5b50610426610a3c3660046151bb565b604081018051805160208201208252606090922091905290565b348015610a6257600080fd5b5061042660015481565b348015610a7857600080fd5b506000546103819060ff1681565b348015610a9257600080fd5b506103ab612417565b348015610aa757600080fd5b50610381610ab63660046151f7565b600d60209081526000928352604080842090915290825290205460ff1681565b348015610ae257600080fd5b50610381610af1366004614e60565b60036020526000908152604090205460ff1681565b61035f610b14366004615225565b612434565b348015610b2557600080fd5b5061049f610b343660046152ea565b63f23a6e6160e01b9695505050505050565b348015610b5257600080fd5b5061035f610b61366004614e60565b6127e0565b348015610b7257600080fd5b50610b86610b81366004615372565b61286e565b60405161038d91906153a2565b348015610b9f57600080fd5b5061035f612caa565b7feb054550c406db3b89dc7016369a66aff0ce40188133281942b92e6188c6b1ef546001600160a01b031690565b604051633e4011b960e01b81523090633e4011b990610bfb9085908590600401615416565b60006040518083038186803b158015610c1357600080fd5b505afa925050508015610c24575060015b610c91573d808015610c52576040519150601f19603f3d011682016040523d82523d6000602084013e610c57565b606091505b5060008082806020019051810190610c6f919061547f565b9150915081610c8157610c8181612e10565b610c8a81612e18565b5050505050565b610c996154c5565b5050565b6000610ca882612e20565b80610cb75750610cb782612e3a565b80610cd257506001600160e01b0319821663152a902d60e11b145b92915050565b60088054610ce5906154db565b80601f0160208091040260200160405190810160405280929190818152602001828054610d11906154db565b8015610d5e5780601f10610d3357610100808354040283529160200191610d5e565b820191906000526020600020905b815481529060010190602001808311610d4157829003601f168201915b505050505081565b60006001600160a01b037f00000000000000000000000052010e220e5c8ef2217d86cfa58da51da39e8ec4163003610db15760405163ea2cbbd560e01b815260040160405180910390fd5b6000838152600660209081526040808320815160a081018352815464ffffffffff8082168352600160281b8204811695830195909552600160501b8104851693820193909352600160781b83049093166060840152600160a01b9091046001600160601b0316608083015291610e2682612e7d565b90506001816007811115610e3c57610e3c6150f7565b14158015610e5c57506003816007811115610e5957610e596150f7565b14155b8015610e7a57506004816007811115610e7757610e776150f7565b14155b15610ea35780604051630821641d60e21b8152600401610e9a9190615515565b60405180910390fd5b5033600090815260028301602052604090205460ff1615610ed957604051630b517d8f60e41b8152336004820152602401610e9a565b3360008181526002840160205260408120805460ff1916600190811790915583519192610f11929091610f0b91615539565b876123d9565b90508082608001818151610f259190615557565b6001600160601b03908116909152835185546020860151604080880151606089015160808a0151909616600160a01b026001600160a01b0364ffffffffff978816600160781b0264ffffffffff60781b19938916600160501b029390931669ffffffffffffffffffff60501b19958916600160281b0269ffffffffffffffffffff1990971698909716979097179490941792909216939093171792909216919091178555517fea45672a2d92b09ff2dd48aa67615f8b5c79d7808b7282fc026a24e00283f78d915061101f908890339085909283526001600160a01b039190911660208301526001600160601b0316604082015260600190565b60405180910390a1602082015164ffffffffff16158015611069575060808201516005546110699190600160601b81046001600160601b031690600160501b900461ffff16613002565b156110ba57825469ffffffffff00000000001916600160281b4264ffffffffff160217835560405186907fe36f8b7448daff4a52e2945db0d1d7a436279cc1d527a45c27835dcbd27f336d90600090a25b50608001516001600160601b0316949350505050565b6000818152600a60205260409020546001600160a01b03163381148061111957506001600160a01b0381166000908152600d6020908152604080832033845290915290205460ff165b6111565760405162461bcd60e51b815260206004820152600e60248201526d1393d517d055551213d49256915160921b6044820152606401610e9a565b6000828152600c602052604080822080546001600160a01b0319166001600160a01b0387811691821790925591518593918516917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591a4505050565b600e546000906001600160a01b03163381146111f257604051633a33dca760e11b81523360048201526001600160a01b0382166024820152604401610e9a565b6001600160a01b037f00000000000000000000000052010e220e5c8ef2217d86cfa58da51da39e8ec416300361123b5760405163ea2cbbd560e01b815260040160405180910390fd5b600e54600f546005546001600160601b03600160a01b90930483169291821691600160601b90910416600061126f8861303e565b90506001600160601b0381166112858484615577565b6001600160601b031610156112a15761129e8383615577565b90505b6112ab8184615557565b92506112b8846001615557565b600e80546001600160601b03928316600160a01b81026001600160a01b0392831617909255600f80548785166bffffffffffffffffffffffff1990911617905560008281526010602090815260408083209587169095558d8316825260049052929092205490975016801561132b578097505b61133f8a6001600160601b0384168a61306f565b6113498a88613191565b5050505050509392505050565b3360009081526003602052604090205460ff1661138657604051633641391960e21b815260040160405180910390fd5b6001600160a01b037f00000000000000000000000052010e220e5c8ef2217d86cfa58da51da39e8ec41630036113cf5760405163ea2cbbd560e01b815260040160405180910390fd5b6000818152600660209081526040808320815160a081018352815464ffffffffff8082168352600160281b8204811695830195909552600160501b8104851693820193909352600160781b83049093166060840152600160a01b9091046001600160601b031660808301529161144482612e7d565b9050600181600781111561145a5761145a6150f7565b1415801561147a57506003816007811115611477576114776150f7565b14155b801561149857506004816007811115611495576114956150f7565b14155b156114b85780604051630821641d60e21b8152600401610e9a9190615515565b5081546001600160a01b03166001600160a01b031917825560405133815283907fc2131db10d833d6b93ae553fa450ea0f6c0c2dfb0160cb3309468bf72718f3eb9060200160405180910390a2505050565b6001600160a01b037f00000000000000000000000052010e220e5c8ef2217d86cfa58da51da39e8ec41630036115535760405163ea2cbbd560e01b815260040160405180910390fd5b60008181526010602052604090205461156f908490849061325d565b61157a83838361328a565b505050565b60008061158a613451565b5060009050805b9250929050565b604051635c9fcd8560e11b8152600b60048201526000907f0000000000000000000000001ca20040ce6ad406bc2a6c89976388829e7fbade6001600160a01b03169063b93f9b0a90602401602060405180830381865afa158015611600573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116249190615597565b9050336001600160a01b038216146116605760405163520b6b7560e01b81523360048201526001600160a01b0382166024820152604401610e9a565b5060005460ff1615611685576040516304e71fd360e31b815260040160405180910390fd5b6001600160a01b037f00000000000000000000000052010e220e5c8ef2217d86cfa58da51da39e8ec41630036116ce5760405163ea2cbbd560e01b815260040160405180910390fd5b600080856001600160a01b03168386866040516116ec9291906155b4565b60006040518083038185875af1925050503d8060008114611729576040519150601f19603f3d011682016040523d82523d6000602084013e61172e565b606091505b5091509150816117415761174181612e10565b7f66cf5924183d7d44caa75d9268a169d7c1422fef43848743d5e1ba32d5833acf8686868660405161177694939291906155ed565b60405180910390a1505050505050565b600e546001600160a01b03163381146117c357604051633a33dca760e11b81523360048201526001600160a01b0382166024820152604401610e9a565b6001600160a01b037f00000000000000000000000052010e220e5c8ef2217d86cfa58da51da39e8ec416300361180c5760405163ea2cbbd560e01b815260040160405180910390fd5b50600e80546001600160a01b0319169055565b6000611829610ba8565b905090565b6001600160a01b03821660009081526007602052604081208054825b818110156118bb57600060026118608484615623565b61186a919061564c565b90508564ffffffffff1684828154811061188657611886615660565b60009182526020909120015464ffffffffff1611156118a7578092506118b5565b6118b2816001615623565b91505b5061184a565b81156118d1576118cc600183615676565b6118d5565b6000195b9695505050505050565b303b8015611900576040516304a41c4d60e51b815260040160405180910390fd5b81516020808201516040808401516060808601519551948801519288015190880151610c9996949592949391906134e7565b33301461193e57600080fd5b600080836001600160a01b0316836040516119599190615689565b600060405180830381855af49150503d8060008114611994576040519150601f19603f3d011682016040523d82523d6000602084013e611999565b606091505b50915091506119c882826040516020016119b49291906156a5565b604051602081830303815290604052612e10565b50505050565b60006119d93361361f565b905080604001516001600160601b03166000148015611a03575060208101516001600160601b0316155b15611a215760405163e6de1cdd60e01b815260040160405180910390fd5b506001600160a01b037f00000000000000000000000052010e220e5c8ef2217d86cfa58da51da39e8ec4163003611a6b5760405163ea2cbbd560e01b815260040160405180910390fd5b6000828152600660205260409020611a8f611a85836156c0565b82600101546136e2565b6040805160a081018252825464ffffffffff8082168352600160281b820481166020840152600160501b8204811693830193909352600160781b81049092166060820152600160a01b9091046001600160601b031660808201526000611af482612e7d565b90506005816007811115611b0a57611b0a6150f7565b14611b2a5780604051630821641d60e21b8152600401610e9a9190615515565b506000611b3d60408501602086016156cc565b64ffffffffff16905060007f0000000000000000000000001ca20040ce6ad406bc2a6c89976388829e7fbade6001600160a01b031663441abbac600f6040518263ffffffff1660e01b8152600401611b9791815260200190565b602060405180830381865afa158015611bb4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bd891906156e7565b604051631106aeeb60e21b8152601760048201529091506000906001600160a01b037f0000000000000000000000001ca20040ce6ad406bc2a6c89976388829e7fbade169063441abbac90602401602060405180830381865afa158015611c43573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c6791906156e7565b90508115611c7b5781831115611c7b578192505b8015611c8d5780831015611c8d578092505b600083856040015164ffffffffff16611ca69190615623565b905080421015611cda576040516303861c4b60e41b815264ffffffffff428116600483015282166024820152604401610e9a565b5050835464ffffffffff60781b1916600160781b648000000000421764ffffffffff1602178455506000905080611d0f610ba8565b6001600160a01b031686604051602401611d2b91815260200190565b60408051601f198184030181529181526020820180516001600160e01b031663e0a8f6f560e01b17905251611d609190615689565b600060405180830381855af49150503d8060008114611d9b576040519150601f19603f3d011682016040523d82523d6000602084013e611da0565b606091505b509150915081611db357611db381612e10565b505060405184907f416e669c63d9a3a5e36ee7cc7e2104b8db28ccd286aa18966e98fa230c73b08c90600090a250505050565b6001600160a01b037f00000000000000000000000052010e220e5c8ef2217d86cfa58da51da39e8ec4163003611e2f5760405163ea2cbbd560e01b815260040160405180910390fd5b61157a838383613721565b6000610cd2826137f1565b60006001600160a01b038216611e8c5760405162461bcd60e51b815260206004820152600c60248201526b5a45524f5f4144445245535360a01b6044820152606401610e9a565b506001600160a01b03166000908152600b602052604090205490565b600554600090600160601b90046001600160601b0316600083815260106020526040902054611edf90670de0b6b3a7640000615700565b610cd2919061564c565b6000611ef883836000196123d9565b9392505050565b60098054610ce5906154db565b336000818152600d602090815260408083206001600160a01b03871680855290835292819020805460ff191686151590811790915590519081529192917f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a35050565b600080611f843361361f565b905080604001516001600160601b03166000148015611fae575060208101516001600160601b0316155b15611fcc5760405163e6de1cdd60e01b815260040160405180910390fd5b506001600160a01b037f00000000000000000000000052010e220e5c8ef2217d86cfa58da51da39e8ec41630036120165760405163ea2cbbd560e01b815260040160405180910390fd5b60026000815461202590615717565b91829055506040805160a08101825264ffffffffff4216815260006020820181905291810182905260608101829052608081019190915290915061207d84604081018051805160208201208252606090922091905290565b600083815260066020908152604091829020600181019390935583518354918501518584015160608701516080909701516001600160601b0316600160a01b026001600160a01b0364ffffffffff988916600160781b0264ffffffffff60781b19938a16600160501b029390931669ffffffffffffffffffff60501b19948a16600160281b0269ffffffffffffffffffff1990971699909516989098179490941791909116919091171793909316929092179055517fea77d064c7d953e57748855e7b0751ea190d1df7505615a4e39336d4d548f6889061216390839033908790615730565b60405180910390a16121758183610d66565b5092915050565b6001600160a01b037f00000000000000000000000052010e220e5c8ef2217d86cfa58da51da39e8ec41630036121c55760405163ea2cbbd560e01b815260040160405180910390fd5b610c8a8585858585613848565b3360009081526003602052604090205460ff1661220257604051633641391960e21b815260040160405180910390fd5b6001600160a01b037f00000000000000000000000052010e220e5c8ef2217d86cfa58da51da39e8ec416300361224b5760405163ea2cbbd560e01b815260040160405180910390fd5b6001600160a01b038116156122b8576001600160a01b03811660009081526003602052604090205460ff16156122945760405163640c1a3360e01b815260040160405180910390fd5b6001600160a01b0381166000908152600360205260409020805460ff191660011790555b33600081815260036020908152604091829020805460ff1916905581519283526001600160a01b038416908301527fddffcdb3bb07c5efc18b0918cf4e3e88c7d42cc05156cdadb2ec12c3b5ff892f910160405180910390a150565b6040805160a081018252600080825260208201819052918101829052606081018290526080810182905250600082815260066020908152604091829020825160a081018452905464ffffffffff8082168352600160281b8204811693830193909352600160501b8104831693820193909352600160781b83049091166060820152600160a01b9091046001600160601b031660808201526123b481612e7d565b9150915091565b60606123c5613451565b505060408051602081019091526000815290565b6000806123e7858585613906565b905080602001518160600151612401578160400151612404565b60005b61240e9190615557565b95945050505050565b6060612421613451565b5060408051602081019091526000815290565b600061243f3361361f565b905080604001516001600160601b03166000148015612469575060208101516001600160601b0316155b156124875760405163e6de1cdd60e01b815260040160405180910390fd5b506040516331a1aa3360e11b8152601560048201527f0000000000000000000000001ca20040ce6ad406bc2a6c89976388829e7fbade6001600160a01b031690636343546690602401602060405180830381865afa1580156124ed573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612511919061577f565b1561252f57604051632fb3e88560e01b815260040160405180910390fd5b6001600160a01b037f00000000000000000000000052010e220e5c8ef2217d86cfa58da51da39e8ec41630036125785760405163ea2cbbd560e01b815260040160405180910390fd5b600088815260066020526040902060018101546125969089906136e2565b6040805160a081018252825464ffffffffff8082168352600160281b820481166020840152600160501b8204811693830193909352600160781b81049092166060820152600160a01b9091046001600160601b0316608082015260006125fb82612e7d565b90506004816007811115612611576126116150f7565b141580156126315750600581600781111561262e5761262e6150f7565b14155b156126515780604051630821641d60e21b8152600401610e9a9190615515565b6004816007811115612665576126656150f7565b036126ca57428a6000015164ffffffffff1610156126ab578951604051632f7e600560e21b815264ffffffffff9182166004820152429091166024820152604401610e9a565b825464ffffffffff60501b1916600160501b4264ffffffffff16021783555b88516020908102818b0120600090815289518202828b0120909152604090206001541461270a57604051633b43666f60e01b815260040160405180910390fd5b825464ffffffffff60781b1916600160781b4264ffffffffff160217835560006127bb8c8c8c8c61273a88613a81565b8d8d8080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050508c8c8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250613aba92505050565b9050806127d257835464ffffffffff60781b191684555b505050505050505050505050565b6001600160a01b037f00000000000000000000000052010e220e5c8ef2217d86cfa58da51da39e8ec41630036128295760405163ea2cbbd560e01b815260040160405180910390fd5b6128353360008361306f565b6040516001600160a01b0382169033907fbfa9be947969a7d4f47eceedb207379702a5e9e8b82ec09d564da75195f8689e90600090a350565b6040805160e081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c08101919091523330146129035760006128b93361361f565b905080604001516001600160601b031660001480156128e3575060208101516001600160601b0316155b156129015760405163e6de1cdd60e01b815260040160405180910390fd5b505b6040516331a1aa3360e11b8152601560048201527f0000000000000000000000001ca20040ce6ad406bc2a6c89976388829e7fbade6001600160a01b031690636343546690602401602060405180830381865afa158015612968573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061298c919061577f565b156129aa57604051632fb3e88560e01b815260040160405180910390fd5b6001600160a01b037f00000000000000000000000052010e220e5c8ef2217d86cfa58da51da39e8ec41630036129f35760405163ea2cbbd560e01b815260040160405180910390fd5b604051635c9fcd8560e11b8152600c60048201526000907f0000000000000000000000001ca20040ce6ad406bc2a6c89976388829e7fbade6001600160a01b03169063b93f9b0a90602401602060405180830381865afa158015612a5b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a7f9190615597565b90507fdda962f630bf2f85c8412f305206a4f363688481dd632689f88ad7022e4cc233858585604051612ab49392919061579c565b60405180910390a160008054630100000081046001600160a01b03169161010090910461ffff1690876001811115612aee57612aee6150f7565b03612b7b57604051631d1972a760e11b81523060048201526001600160a01b03838116602483015261ffff83166044830152841690633a32e54e90479060640160e06040518083038185885af1158015612b4c573d6000803e3d6000fd5b50505050506040513d601f19601f82011682018060405250810190612b7191906157db565b9350505050611ef8565b6001876001811115612b8f57612b8f6150f7565b14612b9c57612b9c6154c5565b6040516370a0823160e01b8152306004820152612c1b9084906001600160a01b038916906370a0823190602401602060405180830381865afa158015612be6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c0a91906156e7565b6001600160a01b0389169190613c06565b60405163eedaf00d60e01b81526001600160a01b038781166004830152306024830152838116604483015261ffff8316606483015284169063eedaf00d9060840160e0604051808303816000875af1158015612c7b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c9f91906157db565b979650505050505050565b604051635c9fcd8560e11b8152600b60048201526000907f0000000000000000000000001ca20040ce6ad406bc2a6c89976388829e7fbade6001600160a01b03169063b93f9b0a90602401602060405180830381865afa158015612d12573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d369190615597565b9050336001600160a01b03821614801590612d6157503360009081526003602052604090205460ff16155b15612d905760405163e670248160e01b81523360048201526001600160a01b0382166024820152604401610e9a565b6001600160a01b037f00000000000000000000000052010e220e5c8ef2217d86cfa58da51da39e8ec4163003612dd95760405163ea2cbbd560e01b815260040160405180910390fd5b6000805460ff191660011781556040517f447e75484d6bdb571b4a92ae14018db7b6dd41f3f02360690c554e1d48f46f879190a150565b805160208201fd5b805160208201f35b6000612e2b82613d38565b80610cd25750610cd282613d6e565b6000612e4582612e20565b80612e6057506380ac58cd60e01b6001600160e01b03198316145b80610cd25750506001600160e01b031916635b5e139f60e01b1490565b805160009064ffffffffff168103612e9757506000919050565b604082015164ffffffffff1615612eec57816060015164ffffffffff16600003612ec357506005919050565b64800000000080836060015164ffffffffff161603612ee457506007919050565b506006919050565b6001600160601b03801682608001516001600160601b031603612f1157506002919050565b6040805160808101825260055464ffffffffff8082168352600160281b82048116602080850191909152600160501b830461ffff1694840194909452600160601b9091046001600160601b031660608301529184015142921615612fcc578164ffffffffff1681602001518560200151612f8b919061588b565b64ffffffffff1611612fa1575060049392505050565b612fb384608001518260600151613d99565b15612fc2575060049392505050565b5060039392505050565b8051845164ffffffffff841691612fe29161588b565b64ffffffffff1611612ff8575060029392505050565b5060019392505050565b60008161ffff16836001600160601b0316856001600160601b031661271061302a9190615700565b613034919061564c565b1015949350505050565b60006001600160601b0382111561306b57604051636f55e21560e11b815260048101839052602401610e9a565b5090565b600061307a8461361f565b6001600160a01b038086166000908152600460205260409020549192501680156130a457806130a6565b845b90506001600160a01b038316156130bd57826130bf565b805b9250600060405180608001604052804264ffffffffff16815260200184602001516001600160601b031681526020016131218761310f87604001516001600160601b03166001600160601b031690565b61311991906158a9565b60170b613dcc565b6001600160601b031681526001600160a01b038681169089161415602090910152905061314e8682613e0d565b6001600160a01b03868116600090815260046020526040902080546001600160a01b0319169186169190911790556131898683868685613fe6565b505050505050565b61319b8282614194565b6001600160a01b0382163b15806132415750604051630a85bd0160e11b80825233600483015260006024830181905260448301849052608060648401526084830152906001600160a01b0384169063150b7a029060a4016020604051808303816000875af1158015613211573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061323591906158d6565b6001600160e01b031916145b610c995760405162461bcd60e51b8152600401610e9a906158f3565b60006132688261429f565b905061327e846132778361591d565b600061306f565b6119c88382600061306f565b6000818152600a60205260409020546001600160a01b038481169116146132e05760405162461bcd60e51b815260206004820152600a60248201526957524f4e475f46524f4d60b01b6044820152606401610e9a565b6001600160a01b03821661332a5760405162461bcd60e51b81526020600482015260116024820152701253959053125117d49150d25412515395607a1b6044820152606401610e9a565b336001600160a01b038416148061336457506001600160a01b0383166000908152600d6020908152604080832033845290915290205460ff165b8061338557506000818152600c60205260409020546001600160a01b031633145b6133c25760405162461bcd60e51b815260206004820152600e60248201526d1393d517d055551213d49256915160921b6044820152606401610e9a565b6001600160a01b038084166000818152600b60209081526040808320805460001901905593861680835284832080546001019055858352600a825284832080546001600160a01b03199081168317909155600c90925284832080549092169091559251849392917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4505050565b604051635c9fcd8560e11b81526004808201526134dd907f0000000000000000000000001ca20040ce6ad406bc2a6c89976388829e7fbade6001600160a01b03169063b93f9b0a90602401602060405180830381865afa1580156134b9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103229190615597565b6134e56154c5565b565b6134f28484846142cc565b60086134fe8882615986565b50600961350b8782615986565b50600e80546001600160a01b0319166001600160a01b038316179055841561361657604051635c9fcd8560e11b8152601660048201527f0000000000000000000000001ca20040ce6ad406bc2a6c89976388829e7fbade6001600160a01b03169063b93f9b0a90602401602060405180830381865afa158015613592573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135b69190615597565b6001600160a01b031663fc9968df866040518263ffffffff1660e01b81526004016135e391815260200190565b600060405180830381600087803b1580156135fd57600080fd5b505af1158015613611573d6000803e3d6000fd5b505050505b50505050505050565b6040805160808101825260008082526020808301829052828401829052606083018290526001600160a01b03851682526007905291909120805480156136db578161366b600183615676565b8154811061367b5761367b615660565b600091825260209182902060408051608081018252929091015464ffffffffff81168352600160281b81046001600160601b0390811694840194909452600160881b810490931690820152600160e81b90910460ff161515606082015292505b5050919050565b60408201805180516020820120825260608420915280821461157a57604051630267877160e11b81526004810182905260248101839052604401610e9a565b61372c83838361150a565b6001600160a01b0382163b15806137d55750604051630a85bd0160e11b8082523360048301526001600160a01b03858116602484015260448301849052608060648401526000608484015290919084169063150b7a029060a4016020604051808303816000875af11580156137a5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137c991906158d6565b6001600160e01b031916145b61157a5760405162461bcd60e51b8152600401610e9a906158f3565b6000818152600a60205260409020546001600160a01b0316806138435760405162461bcd60e51b815260206004820152600a6024820152691393d517d3525395115160b21b6044820152606401610e9a565b919050565b61385385858561150a565b6001600160a01b0384163b15806138ea5750604051630a85bd0160e11b808252906001600160a01b0386169063150b7a029061389b9033908a90899089908990600401615a45565b6020604051808303816000875af11580156138ba573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138de91906158d6565b6001600160e01b031916145b610c8a5760405162461bcd60e51b8152600401610e9a906158f3565b6040805160808101825260008082526020808301829052828401829052606083018290526001600160a01b0387168252600790529190912080548015613a7857808410801561398057508464ffffffffff1682858154811061396a5761396a615660565b60009182526020909120015464ffffffffff1611155b80156139d35750613992600182615676565b8414806139d3575064ffffffffff8516826139ae866001615623565b815481106139be576139be615660565b60009182526020909120015464ffffffffff16115b15613a51578184815481106139ea576139ea615660565b600091825260209182902060408051608081018252929091015464ffffffffff81168352600160281b81046001600160601b0390811694840194909452600160881b810490931690820152600160e81b90910460ff16151560608201529250611ef8915050565b613a5b868661182e565b93506000198414613a78578184815481106139ea576139ea615660565b50509392505050565b6080810151600554600091613aa591600160601b90046001600160601b0316613d99565b15613ab257506001919050565b506000919050565b6000806040518060e001604052808a8152602001896040015181526020018581526020018481526020018681526020018881526020018781525090506060600080613b03610ba8565b6001600160a01b031684604051602401613b1d9190615ab4565b60408051601f198184030181529181526020820180516001600160e01b031663a7c8a3f960e01b17905251613b529190615689565b600060405180830381855af49150503d8060008114613b8d576040519150601f19603f3d011682016040523d82523d6000602084013e613b92565b606091505b509150915081613ba557613ba581612e10565b80806020019051810190613bb99190615b94565b92505050897fc98fbf8f20b11b050a9541d12aee1c11fcd31e8e42975cc885fb3d33a6accc823383604051613bef929190615416565b60405180910390a251159998505050505050505050565b6040516001600160a01b03838116602483015260448201839052600091829186169060640160408051601f198184030181529181526020820180516001600160e01b031663a9059cbb60e01b17905251613c609190615689565b6000604051808303816000865af19150503d8060008114613c9d576040519150601f19603f3d011682016040523d82523d6000602084013e613ca2565b606091505b50915091508115613d05578051600003613ce557843b600081900361318957604051639fe23a3960e01b81526001600160a01b0387166004820152602401610e9a565b80806020019051810190613cf9919061577f565b15613d05575050505050565b604051631702a98760e11b81526001600160a01b0380871660048301528516602482015260448101849052606401610e9a565b60006301ffc9a760e01b6001600160e01b031983161480610cd257506001600160e01b03198216630a85bd0160e11b1492915050565b6000613d7982613d38565b80610cd257506001600160e01b03198216630271189760e51b1492915050565b60008082613da985612710615bc8565b613db39190615bf3565b61270f6001600160601b03919091161015949350505050565b6000808260170b1280613de957506001600160601b03601783900b135b1561306b576040516394e08f6160e01b8152601783900b6004820152602401610e9a565b6001600160a01b038216600090815260076020526040902080548015613f5c57600082613e3b600184615676565b81548110613e4b57613e4b615660565b600091825260209182902060408051608081018252919092015464ffffffffff8082168084526001600160601b03600160281b8404811696850196909652600160881b83049095169383019390935260ff600160e81b90910416151560608201528651909350169003613f5a578383613ec5600185615676565b81548110613ed557613ed5615660565b60009182526020918290208351910180549284015160408501516060909501511515600160e81b0260ff60e81b196001600160601b03968716600160881b0216600160881b600160f01b031996909216600160281b026001600160881b031990951664ffffffffff909416939093179390931793909316919091171790555050505050565b505b50805460018101825560009182526020918290208351910180549284015160408501516060909501511515600160e81b0260ff60e81b196001600160601b03968716600160881b0216600160881b600160f01b031996909216600160281b026001600160881b031990951664ffffffffff9094169390931793909317939093169190911717905550565b6001600160a01b038316158061400357506001600160a01b038416155b156140215760405163e5ec2d2560e01b815260040160405180910390fd5b846001600160a01b0316846001600160a01b0316141580156140555750826001600160a01b0316846001600160a01b031614155b156140cf5760006140658561361f565b9050600060405180608001604052804264ffffffffff168152602001856040015184602001516140959190615577565b6001600160601b0316815260200183604001516001600160601b031681526020018360600151151581525090506140cc8682613e0d565b50505b846001600160a01b0316836001600160a01b031614610c8a5760006140f38461361f565b905060008260400151826020015161410b9190615557565b9050856001600160a01b0316856001600160a01b0316036141385760408401516141359082615577565b90505b600060405180608001604052804264ffffffffff168152602001836001600160601b0316815260200184604001516001600160601b0316815260200184606001511515815250905061418a8682613e0d565b5050505050505050565b6001600160a01b0382166141de5760405162461bcd60e51b81526020600482015260116024820152701253959053125117d49150d25412515395607a1b6044820152606401610e9a565b6000818152600a60205260409020546001600160a01b0316156142345760405162461bcd60e51b815260206004820152600e60248201526d1053149150511657d3525395115160921b6044820152606401610e9a565b6001600160a01b0382166000818152600b6020908152604080832080546001019055848352600a90915280822080546001600160a01b0319168417905551839291907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a45050565b60006001600160bf1b0382111561306b5760405163e9a5989b60e01b815260048101839052602401610e9a565b6127108360a0015161ffff1611156143035760a08301516040516323dd0d6d60e11b815261ffff9091166004820152602401610e9a565b612710836060015161ffff16111561433a5760608301516040516323dd0d6d60e11b815261ffff9091166004820152602401610e9a565b604051635c9fcd8560e11b8152600260048201526143dc907f0000000000000000000000001ca20040ce6ad406bc2a6c89976388829e7fbade6001600160a01b03169063b93f9b0a90602401602060405180830381865afa1580156143a3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906143c79190615597565b6040518060200160405280600081525061454e565b604080516080808201835260208681015164ffffffffff9081168085528886015190911691840182905260608089015161ffff908116968601879052938901516001600160601b031694018490526005805469ffffffffffffffffffff1916909117600160281b909202919091176dffffffffffffffffffffffffffff60501b1916600160501b9094026bffffffffffffffffffffffff60601b191693909317600160601b9092029190911790915560a08401516000805460c0870151610100600160b81b031990911661010093909416929092026301000000600160b81b0319169290921763010000006001600160a01b03909216919091021790556144e3828261462f565b60005b8351518110156119c8576001600360008660000151848151811061450c5761450c615660565b6020908102919091018101516001600160a01b03168252810191909152604001600020805460ff191691151591909117905561454781615717565b90506144e6565b7feb054550c406db3b89dc7016369a66aff0ce40188133281942b92e6188c6b1ef80546001600160a01b031981166001600160a01b03858116918217845560405192169160009182916145a79085908890602401615416565b60408051601f198184030181529181526020820180516001600160e01b031663347d5e2560e21b179052516145dc9190615689565b600060405180830381855af49150503d8060008114614617576040519150601f19603f3d011682016040523d82523d6000602084013e61461c565b606091505b5091509150816131895761318981612e10565b8051825114614651576040516357cc2fc760e01b815260040160405180910390fd5b815160209081028184012060009081528251820282840120909152604090206001555050565b6001600160e01b03198116811461468d57600080fd5b50565b6000602082840312156146a257600080fd5b8135611ef881614677565b60005b838110156146c85781810151838201526020016146b0565b50506000910152565b600081518084526146e98160208601602086016146ad565b601f01601f19169290920160200192915050565b602081526000611ef860208301846146d1565b60006020828403121561472257600080fd5b5035919050565b6000806040838503121561473c57600080fd5b50508035926020909101359150565b6001600160a01b038116811461468d57600080fd5b80356138438161474b565b6000806040838503121561477e57600080fd5b82356147898161474b565b946020939093013593505050565b6000806000606084860312156147ac57600080fd5b83356147b78161474b565b92506020840135915060408401356147ce8161474b565b809150509250925092565b634e487b7160e01b600052604160045260246000fd5b604051608081016001600160401b0381118282101715614811576148116147d9565b60405290565b60405160e081016001600160401b0381118282101715614811576148116147d9565b604051601f8201601f191681016001600160401b0381118282101715614861576148616147d9565b604052919050565b60006001600160401b03821115614882576148826147d9565b50601f01601f191660200190565b600082601f8301126148a157600080fd5b81356148b46148af82614869565b614839565b8181528460208386010111156148c957600080fd5b816020850160208301376000918101602001919091529392505050565b600080600080608085870312156148fc57600080fd5b84356149078161474b565b935060208501356149178161474b565b92506040850135915060608501356001600160401b0381111561493957600080fd5b61494587828801614890565b91505092959194509250565b60008060006060848603121561496657600080fd5b83356149718161474b565b925060208401356149818161474b565b929592945050506040919091013590565b60008083601f8401126149a457600080fd5b5081356001600160401b038111156149bb57600080fd5b60208301915083602082850101111561159157600080fd5b600080600080606085870312156149e957600080fd5b84356149f48161474b565b935060208501356001600160401b03811115614a0f57600080fd5b614a1b87828801614992565b9598909750949560400135949350505050565b803564ffffffffff8116811461384357600080fd5b60008060408385031215614a5657600080fd5b8235614a618161474b565b9150614a6f60208401614a2e565b90509250929050565b60006001600160401b03821115614a9157614a916147d9565b5060051b60200190565b600082601f830112614aac57600080fd5b81356020614abc6148af83614a78565b82815260059290921b84018101918181019086841115614adb57600080fd5b8286015b84811015614aff578035614af28161474b565b8352918301918301614adf565b509695505050505050565b803561ffff8116811461384357600080fd5b80356001600160601b038116811461384357600080fd5b600082601f830112614b4457600080fd5b81356020614b546148af83614a78565b82815260059290921b84018101918181019086841115614b7357600080fd5b8286015b84811015614aff578035614b8a8161474b565b8352918301918301614b77565b600082601f830112614ba857600080fd5b81356020614bb86148af83614a78565b82815260059290921b84018101918181019086841115614bd757600080fd5b8286015b84811015614aff5780358352918301918301614bdb565b60006020808385031215614c0557600080fd5b82356001600160401b0380821115614c1c57600080fd5b9084019060808287031215614c3057600080fd5b614c386147ef565b823582811115614c4757600080fd5b830160808189031215614c5957600080fd5b614c616147ef565b813584811115614c7057600080fd5b820160e0818b031215614c8257600080fd5b614c8a614817565b813586811115614c9957600080fd5b614ca58c828501614a9b565b825250614cb3888301614a2e565b888201526040614cc4818401614a2e565b818301526060614cd5818501614b0a565b81840152614ce560808501614b1c565b6080840152614cf660a08501614b0a565b60a0840152614d0760c08501614760565b60c084015282855289860135935087841115614d2257600080fd5b614d2e8d858801614890565b8a86015281860135935087841115614d4557600080fd5b614d518d858801614890565b858301529485013585850152838652878901359487861115614d7257600080fd5b614d7e8d878b01614b33565b8a880152818901359950878a1115614d9557600080fd5b614da18d8b8b01614b97565b82880152614db0818a01614760565b9087015250939a9950505050505050505050565b60008060408385031215614dd757600080fd5b8235614de28161474b565b915060208301356001600160401b03811115614dfd57600080fd5b614e0985828601614890565b9150509250929050565b60008060408385031215614e2657600080fd5b8235915060208301356001600160401b03811115614e4357600080fd5b830160608186031215614e5557600080fd5b809150509250929050565b600060208284031215614e7257600080fd5b8135611ef88161474b565b801515811461468d57600080fd5b60008060408385031215614e9e57600080fd5b8235614ea98161474b565b91506020830135614e5581614e7d565b600060608284031215614ecb57600080fd5b604051606081016001600160401b038282108183111715614eee57614eee6147d9565b81604052829350614efe85614a2e565b8352614f0c60208601614a2e565b60208401526040850135915080821115614f2557600080fd5b50614f3285828601614890565b6040830152505092915050565b60008060408385031215614f5257600080fd5b82356001600160401b03811115614f6857600080fd5b614f7485828601614eb9565b95602094909401359450505050565b600080600080600060808688031215614f9b57600080fd5b8535614fa68161474b565b94506020860135614fb68161474b565b93506040860135925060608601356001600160401b03811115614fd857600080fd5b614fe488828901614992565b969995985093965092949392505050565b60008083601f84011261500757600080fd5b5081356001600160401b0381111561501e57600080fd5b6020830191508360208260051b850101111561159157600080fd5b60008060008060008060008060a0898b03121561505557600080fd5b88356150608161474b565b975060208901356150708161474b565b965060408901356001600160401b038082111561508c57600080fd5b6150988c838d01614ff5565b909850965060608b01359150808211156150b157600080fd5b6150bd8c838d01614ff5565b909650945060808b01359150808211156150d657600080fd5b506150e38b828c01614992565b999c989b5096995094979396929594505050565b634e487b7160e01b600052602160045260246000fd5b6008811061511d5761511d6150f7565b9052565b60c0810161512f828561510d565b64ffffffffff808451166020840152806020850151166040840152806040850151166060840152806060850151166080840152506001600160601b0360808401511660a08301529392505050565b60008060006060848603121561519257600080fd5b833561519d8161474b565b92506151ab60208501614a2e565b9150604084013590509250925092565b6000602082840312156151cd57600080fd5b81356001600160401b038111156151e357600080fd5b6151ef84828501614eb9565b949350505050565b6000806040838503121561520a57600080fd5b82356152158161474b565b91506020830135614e558161474b565b60008060008060008060008060c0898b03121561524157600080fd5b8835975060208901356001600160401b038082111561525f57600080fd5b61526b8c838d01614eb9565b985060408b013591508082111561528157600080fd5b61528d8c838d01614b33565b975060608b01359150808211156152a357600080fd5b6152af8c838d01614b97565b965060808b01359150808211156152c557600080fd5b6152d18c838d01614992565b909650945060a08b01359150808211156150d657600080fd5b60008060008060008060a0878903121561530357600080fd5b863561530e8161474b565b9550602087013561531e8161474b565b9450604087013593506060870135925060808701356001600160401b0381111561534757600080fd5b61535389828a01614992565b979a9699509497509295939492505050565b6002811061468d57600080fd5b60008060006060848603121561538757600080fd5b833561497181615365565b6002811061511d5761511d6150f7565b600060e0820190506153b5828451615392565b60208301516020830152604083015160018060a01b038082166040850152806060860151166060850152806080860151166080850152505060a08301516001600160801b0380821660a08501528060c08601511660c0850152505092915050565b6001600160a01b03831681526040602082018190526000906151ef908301846146d1565b600082601f83011261544b57600080fd5b81516154596148af82614869565b81815284602083860101111561546e57600080fd5b6151ef8260208301602087016146ad565b6000806040838503121561549257600080fd5b825161549d81614e7d565b60208401519092506001600160401b038111156154b957600080fd5b614e098582860161543a565b634e487b7160e01b600052600160045260246000fd5b600181811c908216806154ef57607f821691505b60208210810361550f57634e487b7160e01b600052602260045260246000fd5b50919050565b60208101610cd2828461510d565b634e487b7160e01b600052601160045260246000fd5b64ffffffffff82811682821603908082111561217557612175615523565b6001600160601b0381811683821601908082111561217557612175615523565b6001600160601b0382811682821603908082111561217557612175615523565b6000602082840312156155a957600080fd5b8151611ef88161474b565b8183823760009101908152919050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b6001600160a01b038516815260606020820181905260009061561290830185876155c4565b905082604083015295945050505050565b80820180821115610cd257610cd2615523565b634e487b7160e01b600052601260045260246000fd5b60008261565b5761565b615636565b500490565b634e487b7160e01b600052603260045260246000fd5b81810381811115610cd257610cd2615523565b6000825161569b8184602087016146ad565b9190910192915050565b82151581526040602082015260006151ef60408301846146d1565b6000610cd23683614eb9565b6000602082840312156156de57600080fd5b611ef882614a2e565b6000602082840312156156f957600080fd5b5051919050565b8082028115828204841417610cd257610cd2615523565b60006001820161572957615729615523565b5060010190565b83815260018060a01b038316602082015260606040820152600064ffffffffff808451166060840152806020850151166080840152506040830151606060a08401526118d560c08401826146d1565b60006020828403121561579157600080fd5b8151611ef881614e7d565b606081016157aa8286615392565b6001600160a01b0393909316602082015260400152919050565b80516001600160801b038116811461384357600080fd5b600060e082840312156157ed57600080fd5b60405160e081018181106001600160401b038211171561580f5761580f6147d9565b604052825161581d81615365565b81526020838101519082015260408301516158378161474b565b6040820152606083015161584a8161474b565b6060820152608083015161585d8161474b565b608082015261586e60a084016157c4565b60a082015261587f60c084016157c4565b60c08201529392505050565b64ffffffffff81811683821601908082111561217557612175615523565b601781810b9083900b016001600160bf1b0381136001600160bf1b031982121715610cd257610cd2615523565b6000602082840312156158e857600080fd5b8151611ef881614677565b60208082526010908201526f155394d0519157d49150d2541251539560821b604082015260600190565b6000601782900b600160bf1b810161593757615937615523565b60000392915050565b601f82111561157a57600081815260208120601f850160051c810160208610156159675750805b601f850160051c820191505b8181101561318957828155600101615973565b81516001600160401b0381111561599f5761599f6147d9565b6159b3816159ad84546154db565b84615940565b602080601f8311600181146159e857600084156159d05750858301515b600019600386901b1c1916600185901b178555613189565b600085815260208120601f198616915b82811015615a17578886015182559484019460019091019084016159f8565b5085821015615a355787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6001600160a01b0386811682528516602082015260408101849052608060608201819052600090612c9f90830184866155c4565b600081518084526020808501945080840160005b83811015615aa957815187529582019590820190600101615a8d565b509495945050505050565b600060208083528351818401528084015160e06040850152615ada6101008501826146d1565b90506040850151601f1980868403016060870152615af883836146d1565b92506060870151915080868403016080870152615b1583836146d1565b608088015160a088810191909152880151878203830160c08901528051808352908601945060009350908501905b80841015615b6c5784516001600160a01b03168252938501936001939093019290850190615b43565b5060c08801519450818782030160e0880152615b888186615a79565b98975050505050505050565b600060208284031215615ba657600080fd5b81516001600160401b03811115615bbc57600080fd5b6151ef8482850161543a565b6001600160601b03818116838216028082169190828114615beb57615beb615523565b505092915050565b60006001600160601b0380841680615c0d57615c0d615636565b9216919091049291505056fea26469706673582212200be9ace9cf91e260ff128ec1313e3ba1d8ac3af33e7e0d741297e426349a86d664736f6c63430008110033

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

0000000000000000000000001ca20040ce6ad406bc2a6c89976388829e7fbade

-----Decoded View---------------
Arg [0] : globals (address): 0x1cA20040cE6aD406bC2A6c89976388829E7fbAde

-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 0000000000000000000000001ca20040ce6ad406bc2a6c89976388829e7fbade


Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading

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.