Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
ProposalExecutionEngine
Compiler Version
v0.8.17+commit.8df45f5f
Optimization Enabled:
Yes with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: GPL-3.0 pragma solidity 0.8.17; import "../utils/Implementation.sol"; import "../utils/LibRawResult.sol"; import "../globals/IGlobals.sol"; import "./IProposalExecutionEngine.sol"; import "./ListOnOpenseaProposal.sol"; import "./ListOnOpenseaAdvancedProposal.sol"; import "./ListOnZoraProposal.sol"; import "./FractionalizeProposal.sol"; import "./ArbitraryCallsProposal.sol"; import "./ProposalStorage.sol"; /// @notice Upgradable implementation of proposal execution logic for parties that use it. /// @dev This contract will be delegatecall'ed into by `Party` proxy instances. contract ProposalExecutionEngine is IProposalExecutionEngine, Implementation, ProposalStorage, ListOnOpenseaProposal, ListOnOpenseaAdvancedProposal, ListOnZoraProposal, FractionalizeProposal, ArbitraryCallsProposal { using LibRawResult for bytes; error UnsupportedProposalTypeError(uint32 proposalType); // The types of proposals supported. // The first 4 bytes of a proposal's `proposalData` determine the proposal // type. // WARNING: This should be append-only. enum ProposalType { Invalid, ListOnOpensea, ListOnZora, Fractionalize, ArbitraryCalls, UpgradeProposalEngineImpl, ListOnOpenseaAdvanced } // Explicit storage bucket for "private" state owned by the `ProposalExecutionEngine`. // See `_getStorage()` for how this is addressed. // // Read this for more context on the pattern motivating this: // https://github.com/dragonfly-xyz/useful-solidity-patterns/tree/main/patterns/explicit-storage-buckets struct Storage { // The hash of the next `progressData` for the current `InProgress` // proposal. This is updated to the hash of the next `progressData` every // time a proposal is executed. This enforces that the next call to // `executeProposal()` receives the correct `progressData`. // If there is no current `InProgress` proposal, this will be 0x0. bytes32 nextProgressDataHash; // The proposal ID of the current, in progress proposal being executed. // `InProgress` proposals need to have `executeProposal()` called on them // multiple times until they complete. Only one proposal may be // in progress at a time, meaning no other proposals can be executed // if this value is nonzero. uint256 currentInProgressProposalId; } event ProposalEngineImplementationUpgraded(address oldImpl, address newImpl); error ZeroProposalIdError(); error MalformedProposalDataError(); error ProposalExecutionBlockedError(uint256 proposalId, uint256 currentInProgressProposalId); error ProposalProgressDataInvalidError( bytes32 actualProgressDataHash, bytes32 expectedProgressDataHash ); error ProposalNotInProgressError(uint256 proposalId); error UnexpectedProposalEngineImplementationError( IProposalExecutionEngine actualImpl, IProposalExecutionEngine expectedImpl ); // The `Globals` contract storing global configuration values. This contract // is immutable and it’s address will never change. IGlobals private immutable _GLOBALS; // Storage slot for `Storage`. // Use a constant, non-overlapping slot offset for the storage bucket. uint256 private constant _STORAGE_SLOT = uint256(keccak256("ProposalExecutionEngine.Storage")); // Set immutables. constructor( IGlobals globals, IOpenseaExchange seaport, IOpenseaConduitController seaportConduitController, IZoraAuctionHouse zoraAuctionHouse, IFractionalV1VaultFactory fractionalVaultFactory ) ListOnOpenseaAdvancedProposal(globals, seaport, seaportConduitController) ListOnZoraProposal(globals, zoraAuctionHouse) FractionalizeProposal(fractionalVaultFactory) ArbitraryCallsProposal(zoraAuctionHouse) { _GLOBALS = globals; } // Used by `Party` to setup the execution engine. // Currently does nothing, but may be changed in future versions. function initialize( address oldImpl, bytes calldata initializeData ) external override onlyDelegateCall { /* NOOP */ } /// @notice Get the current `InProgress` proposal ID. /// @dev With this version, only one proposal may be in progress at a time. function getCurrentInProgressProposalId() external view returns (uint256 id) { return _getStorage().currentInProgressProposalId; } /// @inheritdoc IProposalExecutionEngine function executeProposal( ExecuteProposalParams memory params ) external onlyDelegateCall returns (bytes memory nextProgressData) { // Must have a valid proposal ID. if (params.proposalId == 0) { revert ZeroProposalIdError(); } Storage storage stor = _getStorage(); uint256 currentInProgressProposalId = stor.currentInProgressProposalId; if (currentInProgressProposalId == 0) { // No proposal is currently in progress. // Mark this proposal as the one in progress. stor.currentInProgressProposalId = params.proposalId; } else if (currentInProgressProposalId != params.proposalId) { // Only one proposal can be in progress at a time. revert ProposalExecutionBlockedError(params.proposalId, currentInProgressProposalId); } { bytes32 nextProgressDataHash = stor.nextProgressDataHash; if (nextProgressDataHash == 0) { // Expecting no progress data. // This is the state if there is no current `InProgress` proposal. assert(currentInProgressProposalId == 0); if (params.progressData.length != 0) { revert ProposalProgressDataInvalidError( keccak256(params.progressData), nextProgressDataHash ); } } else { // Expecting progress data. bytes32 progressDataHash = keccak256(params.progressData); // Progress data must match the one stored. if (nextProgressDataHash != progressDataHash) { revert ProposalProgressDataInvalidError(progressDataHash, nextProgressDataHash); } } // Temporarily set the expected next progress data hash to an // unachievable constant to act as a reentrancy guard. stor.nextProgressDataHash = bytes32(type(uint256).max); } // Note that we do not enforce that the proposal has not been executed // (and completed) before in this contract. That is enforced by PartyGovernance. // Execute the proposal. ProposalType pt; (pt, params.proposalData) = _extractProposalType(params.proposalData); nextProgressData = _execute(pt, params); // If progress data is empty, the proposal is complete. if (nextProgressData.length == 0) { stor.currentInProgressProposalId = 0; stor.nextProgressDataHash = 0; } else { // Remember the next progress data. stor.nextProgressDataHash = keccak256(nextProgressData); } } /// @inheritdoc IProposalExecutionEngine function cancelProposal(uint256 proposalId) external onlyDelegateCall { // Must be a valid proposal ID. if (proposalId == 0) { revert ZeroProposalIdError(); } Storage storage stor = _getStorage(); { // Must be the current InProgress proposal. uint256 currentInProgressProposalId = stor.currentInProgressProposalId; if (currentInProgressProposalId != proposalId) { revert ProposalNotInProgressError(proposalId); } } // Clear the current InProgress proposal ID and next progress data. stor.currentInProgressProposalId = 0; stor.nextProgressDataHash = 0; } // Switch statement used to execute the right proposal. function _execute( ProposalType pt, ExecuteProposalParams memory params ) internal virtual returns (bytes memory nextProgressData) { if (pt == ProposalType.ListOnOpensea) { nextProgressData = _executeListOnOpensea(params); } else if (pt == ProposalType.ListOnOpenseaAdvanced) { nextProgressData = _executeListOnOpenseaAdvanced(params); } else if (pt == ProposalType.ListOnZora) { nextProgressData = _executeListOnZora(params); } else if (pt == ProposalType.Fractionalize) { nextProgressData = _executeFractionalize(params); } else if (pt == ProposalType.ArbitraryCalls) { nextProgressData = _executeArbitraryCalls(params); } else if (pt == ProposalType.UpgradeProposalEngineImpl) { _executeUpgradeProposalsImplementation(params.proposalData); } else { revert UnsupportedProposalTypeError(uint32(pt)); } } // Destructively pops off the first 4 bytes of `proposalData` to determine // the type. This modifies `proposalData` and returns the updated // pointer to it. function _extractProposalType( bytes memory proposalData ) private pure returns (ProposalType proposalType, bytes memory offsetProposalData) { // First 4 bytes is proposal type. While the proposal type could be // stored in just 1 byte, this makes it easier to encode with // `abi.encodeWithSelector`. if (proposalData.length < 4) { revert MalformedProposalDataError(); } assembly { // By reading 4 bytes into the length prefix, the leading 4 bytes // of the data will be in the lower bits of the read word. proposalType := and(mload(add(proposalData, 4)), 0xffffffff) mstore(add(proposalData, 4), sub(mload(proposalData), 4)) offsetProposalData := add(proposalData, 4) } require(proposalType != ProposalType.Invalid); require(uint8(proposalType) <= uint8(type(ProposalType).max)); } // Upgrade implementation to the latest version. function _executeUpgradeProposalsImplementation(bytes memory proposalData) private { (address expectedImpl, bytes memory initData) = abi.decode(proposalData, (address, bytes)); // Always upgrade to latest implementation stored in `_GLOBALS`. IProposalExecutionEngine newImpl = IProposalExecutionEngine( _GLOBALS.getAddress(LibGlobals.GLOBAL_PROPOSAL_ENGINE_IMPL) ); if (expectedImpl != address(newImpl)) { revert UnexpectedProposalEngineImplementationError( newImpl, IProposalExecutionEngine(expectedImpl) ); } _initProposalImpl(newImpl, initData); emit ProposalEngineImplementationUpgraded(address(IMPL), expectedImpl); } // Retrieve the explicit storage bucket for the ProposalExecutionEngine logic. function _getStorage() internal pure returns (Storage storage stor) { uint256 slot = _STORAGE_SLOT; assembly { stor.slot := slot } } }
// 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); }
// 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); }
// 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 multiSig() external view returns (address); 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; }
// 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; uint256 internal constant GLOBAL_ROLLING_AUCTION_CF_IMPL = 24; uint256 internal constant GLOBAL_COLLECTION_BATCH_BUY_CF_IMPL = 25; uint256 internal constant GLOBAL_METADATA_REGISTRY = 26; }
// 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); }
// 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 {} }
// 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 private constant UINT40_HIGH_BIT = 1 << 39; uint96 private constant 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 pure virtual override(ERC721Receiver, ERC1155Receiver) 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); } } }
// 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 view override 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. } }
// SPDX-License-Identifier: GPL-3.0 pragma solidity 0.8.17; import "../tokens/IERC721.sol"; import "../tokens/IERC721Receiver.sol"; import "../tokens/ERC1155Receiver.sol"; import "../utils/LibSafeERC721.sol"; import "../utils/LibAddress.sol"; import "../vendor/markets/IZoraAuctionHouse.sol"; import "./vendor/IOpenseaExchange.sol"; import "./LibProposal.sol"; import "./IProposalExecutionEngine.sol"; // Implements arbitrary call proposals. Inherited by the `ProposalExecutionEngine`. // This contract will be delegatecall'ed into by `Party` proxy instances. contract ArbitraryCallsProposal { using LibSafeERC721 for IERC721; using LibAddress for address payable; struct ArbitraryCall { // The call target. address payable target; // Amount of ETH to attach to the call. uint256 value; // Calldata. bytes data; // Hash of the successful return data of the call. // If 0x0, no return data checking will occur for this call. bytes32 expectedResultHash; } error PreciousLostError(IERC721 token, uint256 tokenId); error CallProhibitedError(address target, bytes data); error ArbitraryCallFailedError(bytes revertData); error UnexpectedCallResultHashError( uint256 idx, bytes32 resultHash, bytes32 expectedResultHash ); error NotEnoughEthAttachedError(uint256 callValue, uint256 ethAvailable); error InvalidApprovalCallLength(uint256 callDataLength); event ArbitraryCallExecuted(uint256 proposalId, uint256 idx, uint256 count); IZoraAuctionHouse private immutable _ZORA; constructor(IZoraAuctionHouse zora) { _ZORA = zora; } function _executeArbitraryCalls( IProposalExecutionEngine.ExecuteProposalParams memory params ) internal returns (bytes memory nextProgressData) { // Get the calls to execute. ArbitraryCall[] memory calls = abi.decode(params.proposalData, (ArbitraryCall[])); // Check whether the proposal was unanimously passed. bool isUnanimous = params.flags & LibProposal.PROPOSAL_FLAG_UNANIMOUS == LibProposal.PROPOSAL_FLAG_UNANIMOUS; // If not unanimous, keep track of which preciouses we had before the calls // so we can check that we still have them later. bool[] memory hadPreciouses = new bool[](params.preciousTokenIds.length); if (!isUnanimous) { for (uint256 i; i < hadPreciouses.length; ++i) { hadPreciouses[i] = _getHasPrecious( params.preciousTokens[i], params.preciousTokenIds[i] ); } } // Can only forward ETH attached to the call. uint256 ethAvailable = msg.value; for (uint256 i; i < calls.length; ++i) { // Execute an arbitrary call. _executeSingleArbitraryCall( i, calls, params.preciousTokens, params.preciousTokenIds, isUnanimous, ethAvailable ); // Update the amount of ETH available for the subsequent calls. ethAvailable -= calls[i].value; emit ArbitraryCallExecuted(params.proposalId, i, calls.length); } // If not a unanimous vote and we had a precious beforehand, // ensure that we still have it now. if (!isUnanimous) { for (uint256 i; i < hadPreciouses.length; ++i) { if (hadPreciouses[i]) { if (!_getHasPrecious(params.preciousTokens[i], params.preciousTokenIds[i])) { revert PreciousLostError( params.preciousTokens[i], params.preciousTokenIds[i] ); } } } } // Refund leftover ETH. if (ethAvailable > 0) { payable(msg.sender).transferEth(ethAvailable); } // No next step, so no progressData. return ""; } function _executeSingleArbitraryCall( uint256 idx, ArbitraryCall[] memory calls, IERC721[] memory preciousTokens, uint256[] memory preciousTokenIds, bool isUnanimous, uint256 ethAvailable ) private { ArbitraryCall memory call = calls[idx]; // Check that the call is not prohibited. if ( !_isCallAllowed(call, isUnanimous, idx, calls.length, preciousTokens, preciousTokenIds) ) { revert CallProhibitedError(call.target, call.data); } // Check that we have enough ETH to execute the call. if (ethAvailable < call.value) { revert NotEnoughEthAttachedError(call.value, ethAvailable); } // Execute the call. (bool s, bytes memory r) = call.target.call{ value: call.value }(call.data); if (!s) { // Call failed. If not optional, revert. revert ArbitraryCallFailedError(r); } else { // Call succeeded. // If we have a nonzero expectedResultHash, check that the result data // from the call has a matching hash. if (call.expectedResultHash != bytes32(0)) { bytes32 resultHash = keccak256(r); if (resultHash != call.expectedResultHash) { revert UnexpectedCallResultHashError(idx, resultHash, call.expectedResultHash); } } } } // Do we possess the precious? function _getHasPrecious( IERC721 preciousToken, uint256 preciousTokenId ) private view returns (bool hasPrecious) { hasPrecious = preciousToken.safeOwnerOf(preciousTokenId) == address(this); } function _isCallAllowed( ArbitraryCall memory call, bool isUnanimous, uint256 callIndex, uint256 callsCount, IERC721[] memory preciousTokens, uint256[] memory preciousTokenIds ) private view returns (bool isAllowed) { // Cannot call ourselves. if (call.target == address(this)) { return false; } if (call.data.length >= 4) { // Get the function selector of the call (first 4 bytes of calldata). bytes4 selector; { bytes memory callData = call.data; assembly { selector := and( mload(add(callData, 32)), 0xffffffff00000000000000000000000000000000000000000000000000000000 ) } } // Non-unanimous proposals restrict what ways some functions can be // called on a precious token. if (!isUnanimous) { // Cannot call `approve()` or `setApprovalForAll()` on the precious // unless it's to revoke approvals. if (selector == IERC721.approve.selector) { // Can only call `approve()` on the precious if the operator is null. (address op, uint256 tokenId) = _decodeApproveCallDataArgs(call.data); if (op != address(0)) { return !LibProposal.isTokenIdPrecious( IERC721(call.target), tokenId, preciousTokens, preciousTokenIds ); } // Can only call `setApprovalForAll()` on the precious if // toggling off. } else if (selector == IERC721.setApprovalForAll.selector) { (, bool isApproved) = _decodeSetApprovalForAllCallDataArgs(call.data); if (isApproved) { return !LibProposal.isTokenPrecious(IERC721(call.target), preciousTokens); } // Can only call cancelAuction on the zora AH if it's the last call // in the sequence. } else if (selector == IZoraAuctionHouse.cancelAuction.selector) { if (call.target == address(_ZORA)) { return callIndex + 1 == callsCount; } } } // Can never call receive hooks on any target. if ( selector == IERC721Receiver.onERC721Received.selector || selector == ERC1155TokenReceiverBase.onERC1155Received.selector || selector == ERC1155TokenReceiverBase.onERC1155BatchReceived.selector ) { return false; } // Disallow calling `validate()` on Seaport. if (selector == IOpenseaExchange.validate.selector) { return false; } } // All other calls are allowed. return true; } // Get the `operator` and `tokenId` from the `approve()` call data. function _decodeApproveCallDataArgs( bytes memory callData ) private pure returns (address operator, uint256 tokenId) { if (callData.length < 68) { revert InvalidApprovalCallLength(callData.length); } assembly { operator := and(mload(add(callData, 36)), 0xffffffffffffffffffffffffffffffffffffffff) tokenId := mload(add(callData, 68)) } } // Get the `operator` and `tokenId` from the `setApprovalForAll()` call data. function _decodeSetApprovalForAllCallDataArgs( bytes memory callData ) private pure returns (address operator, bool isApproved) { if (callData.length < 68) { revert InvalidApprovalCallLength(callData.length); } assembly { operator := and(mload(add(callData, 36)), 0xffffffffffffffffffffffffffffffffffffffff) isApproved := xor(iszero(mload(add(callData, 68))), 1) } } }
// SPDX-License-Identifier: GPL-3.0 pragma solidity 0.8.17; import "../tokens/IERC721.sol"; import "../party/PartyGovernance.sol"; import "./IProposalExecutionEngine.sol"; import "./vendor/FractionalV1.sol"; // Implements fractionalizing an NFT to ERC20s on Fractional V1. Inherited by the `ProposalExecutionEngine`. // This contract will be delegatecall'ed into by `Party` proxy instances. contract FractionalizeProposal { struct FractionalizeProposalData { // The ERC721 token contract to fractionalize. IERC721 token; // The ERC721 token ID to fractionalize. uint256 tokenId; } event FractionalV1VaultCreated( IERC721 indexed token, uint256 indexed tokenId, uint256 vaultId, IERC20 vault ); /// @notice Deployment of https://github.com/fractional-company/contracts/blob/master/src/ERC721TokenVault.sol. IFractionalV1VaultFactory public immutable VAULT_FACTORY; // Set the `VAULT_FACTORY`. constructor(IFractionalV1VaultFactory vaultFactory) { VAULT_FACTORY = vaultFactory; } // Fractionalize an NFT held by this party on Fractional V1. function _executeFractionalize( IProposalExecutionEngine.ExecuteProposalParams memory params ) internal returns (bytes memory nextProgressData) { // Decode the proposal data. FractionalizeProposalData memory data = abi.decode( params.proposalData, (FractionalizeProposalData) ); // The supply of fractional vault ERC20 tokens will be equal to the total // voting power of the party. uint256 supply = PartyGovernance(address(this)).getGovernanceValues().totalVotingPower; // Create a vault around the NFT. data.token.approve(address(VAULT_FACTORY), data.tokenId); uint256 vaultId = VAULT_FACTORY.mint( IERC721(address(this)).name(), IERC721(address(this)).symbol(), data.token, data.tokenId, supply, // Since we are distributing the entire supply immediately after // fractionalizing, in practice setting an initial reserve price // does not do anything because it will get reset to 0 after the // distribution is created. 0, 0 ); // Get the vault we just created. IFractionalV1Vault vault = VAULT_FACTORY.vaults(vaultId); // Check that we now hold the correct amount of fractional tokens. // Should always succeed. assert(vault.balanceOf(address(this)) == supply); // Remove ourselves as curator. Set to `address(1)` to avoid issues with // reverting when minting to `address(0)`. vault.updateCurator(address(1)); emit FractionalV1VaultCreated(data.token, data.tokenId, vaultId, vault); // Create distribution for fractional tokens for party. PartyGovernance(address(this)).distribute( ITokenDistributor.TokenType.Erc20, address(vault), vaultId ); // Nothing left to do. return ""; } }
// 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; }
// 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; } }
// SPDX-License-Identifier: GPL-3.0 pragma solidity 0.8.17; import "../globals/IGlobals.sol"; import "../globals/LibGlobals.sol"; import "../tokens/IERC721.sol"; import "../tokens/IERC1155.sol"; import "../utils/LibSafeCast.sol"; import "./vendor/IOpenseaExchange.sol"; import "./vendor/IOpenseaConduitController.sol"; import "./OpenseaHelpers.sol"; import "./ZoraHelpers.sol"; import "./LibProposal.sol"; import "./IProposalExecutionEngine.sol"; // Implements proposal listing an NFT on OpenSea (Seaport) with extra // parameters. Inherited by the `ProposalExecutionEngine`. // This contract will be delegatecall'ed into by `Party` proxy instances. abstract contract ListOnOpenseaAdvancedProposal is OpenseaHelpers, ZoraHelpers { using LibSafeCast for uint256; // ABI-encoded `proposalData` passed into execute. struct OpenseaAdvancedProposalData { // The starting price (in ETH) when the listing is created. // This is also the reserve bid for the safety Zora auction. uint256 startPrice; // The ending price (in ETH) when the listing expires. // Unless listing as a dutch auction, this should be the same as `startPrice` in most cases. uint256 endPrice; // How long the listing is valid for. uint40 duration; // The type of the NFT token. TokenType tokenType; // The NFT token contract. address token; // the NFT token ID. uint256 tokenId; // Fees the taker must pay when filling the listing. uint256[] fees; // Respective recipients for each fee. address payable[] feeRecipients; // The first 4 bytes of the hash of a domain to attribute the listing to. // https://opensea.notion.site/opensea/Proposal-for-Seaport-Order-Attributions-via-Arbitrary-Domain-Hash-d0ad30b994ba48278c6e922983175285 bytes4 domainHashPrefix; } enum TokenType { // The NFT is an ERC721. ERC721, // The NFT is an ERC1155. ERC1155 } enum ListOnOpenseaStep { // The proposal hasn't been executed yet. None, // The NFT was placed in a Zora auction. ListedOnZora, // The Zora auction was either skipped or cancelled. RetrievedFromZora, // The NFT was listed on OpenSea. ListedOnOpenSea } // ABI-encoded `progressData` passed into execute in the `ListedOnOpenSea` step. struct OpenseaProgressData { // Hash of the OS order that was listed. bytes32 orderHash; // Conduit approved to spend the NFT. address conduit; // Expiration timestamp of the listing. uint40 expiry; } error OpenseaOrderStillActiveError( bytes32 orderHash, address token, uint256 tokenId, uint256 expiry ); error InvalidFeeRecipients(); event OpenseaOrderListed( IOpenseaExchange.OrderParameters orderParams, bytes32 orderHash, IERC721 token, uint256 tokenId, uint256 listPrice, uint256 expiry ); event OpenseaAdvancedOrderListed( IOpenseaExchange.OrderParameters orderParams, bytes32 orderHash, address token, uint256 tokenId, uint256 startPrice, uint256 endPrice, uint256 expiry ); event OpenseaOrderSold(bytes32 orderHash, IERC721 token, uint256 tokenId, uint256 listPrice); event OpenseaAdvancedOrderSold( bytes32 orderHash, address token, uint256 tokenId, uint256 startPrice, uint256 endPrice ); event OpenseaOrderExpired(bytes32 orderHash, address token, uint256 tokenId, uint256 expiry); /// @notice The Seaport contract. IOpenseaExchange public immutable SEAPORT; /// @notice The Seaport conduit controller. IOpenseaConduitController public immutable CONDUIT_CONTROLLER; // The `Globals` contract storing global configuration values. This contract // is immutable and it’s address will never change. IGlobals private immutable _GLOBALS; // Set immutables. constructor( IGlobals globals, IOpenseaExchange seaport, IOpenseaConduitController conduitController ) { SEAPORT = seaport; CONDUIT_CONTROLLER = conduitController; _GLOBALS = globals; } // Try to create a listing (ultimately) on OpenSea (Seaport). // Creates a listing on Zora auction house for list price first. When that ends, // calling this function again will list on OpenSea. When that ends, // calling this function again will cancel the listing. function _executeListOnOpenseaAdvanced( IProposalExecutionEngine.ExecuteProposalParams memory params ) internal returns (bytes memory nextProgressData) { OpenseaAdvancedProposalData memory data = abi.decode( params.proposalData, (OpenseaAdvancedProposalData) ); return _executeAdvancedOpenseaProposal(params, data); } function _executeAdvancedOpenseaProposal( IProposalExecutionEngine.ExecuteProposalParams memory params, OpenseaAdvancedProposalData memory data ) internal override returns (bytes memory nextProgressData) { bool isUnanimous = params.flags & LibProposal.PROPOSAL_FLAG_UNANIMOUS == LibProposal.PROPOSAL_FLAG_UNANIMOUS; // If there is no `progressData` passed in, we're on the first step, // otherwise parse the first word of the `progressData` as the current step. ListOnOpenseaStep step = params.progressData.length == 0 ? ListOnOpenseaStep.None : abi.decode(params.progressData, (ListOnOpenseaStep)); if (step == ListOnOpenseaStep.None) { // First time executing the proposal. if ( !isUnanimous && LibProposal.isTokenIdPrecious( IERC721(data.token), data.tokenId, params.preciousTokens, params.preciousTokenIds ) ) { // Not a unanimous vote and the token is precious, so list on Zora // auction house first. uint40 zoraTimeout = uint40( _GLOBALS.getUint256(LibGlobals.GLOBAL_OS_ZORA_AUCTION_TIMEOUT) ); uint40 zoraDuration = uint40( _GLOBALS.getUint256(LibGlobals.GLOBAL_OS_ZORA_AUCTION_DURATION) ); if (zoraTimeout != 0) { uint256 auctionId = _createZoraAuction( data.startPrice, zoraTimeout, zoraDuration, IERC721(data.token), data.tokenId ); // Return the next step and data required to execute that step. return abi.encode( ListOnOpenseaStep.ListedOnZora, ZoraProgressData({ auctionId: auctionId, minExpiry: (block.timestamp + zoraTimeout).safeCastUint256ToUint40() }) ); } } // Unanimous vote, not a precious, or no Zora duration. // Advance past the Zora auction phase by pretending we already // retrieved it from Zora. step = ListOnOpenseaStep.RetrievedFromZora; } if (step == ListOnOpenseaStep.ListedOnZora) { // The last time this proposal was executed, we listed it on Zora. // Now retrieve it from Zora. (, ZoraProgressData memory zpd) = abi.decode( params.progressData, (uint8, ZoraProgressData) ); // Try to settle the Zora auction. This will revert if the auction // is still ongoing. ZoraAuctionStatus statusCode = _settleZoraAuction( zpd.auctionId, zpd.minExpiry, IERC721(data.token), data.tokenId ); if (statusCode == ZoraAuctionStatus.Sold || statusCode == ZoraAuctionStatus.Cancelled) { // Auction sold or was cancelled. If it sold, there is nothing left to do. // If it was cancelled, we cannot safely proceed with the listing. Return // empty progress data to indicate there are no more steps to // execute. return ""; } // The auction simply expired before anyone bid on it. We have the NFT // back now so move on to listing it on OpenSea immediately. step = ListOnOpenseaStep.RetrievedFromZora; } if (step == ListOnOpenseaStep.RetrievedFromZora) { // This step occurs if either: // 1) This is the first time this proposal is being executed and // it is a unanimous vote or the NFT is not precious (guarded) // so we intentionally skip the Zora listing step. // 2) The last time this proposal was executed, we settled an expired // (no bids) Zora auction and can now proceed to the OpenSea // listing step. { // Clamp the order duration to the global minimum and maximum. uint40 minDuration = uint40( _GLOBALS.getUint256(LibGlobals.GLOBAL_OS_MIN_ORDER_DURATION) ); uint40 maxDuration = uint40( _GLOBALS.getUint256(LibGlobals.GLOBAL_OS_MAX_ORDER_DURATION) ); if (minDuration != 0 && data.duration < minDuration) { data.duration = minDuration; } else if (maxDuration != 0 && data.duration > maxDuration) { data.duration = maxDuration; } } uint256 expiry = block.timestamp + uint256(data.duration); (address conduit, bytes32 conduitKey) = _approveConduit( data.token, data.tokenId, data.tokenType ); bytes32 orderHash = _listOnOpensea(data, conduitKey, expiry); return abi.encode(ListOnOpenseaStep.ListedOnOpenSea, orderHash, conduit, expiry); } assert(step == ListOnOpenseaStep.ListedOnOpenSea); // The last time this proposal was executed, we listed it on OpenSea. // Now try to settle the listing (either it has expired or been filled). (, OpenseaProgressData memory opd) = abi.decode( params.progressData, (uint8, OpenseaProgressData) ); _cleanUpListing( opd.orderHash, opd.conduit, opd.expiry, data.token, data.tokenId, data.tokenType, data.startPrice, data.endPrice ); // This is the last possible step so return empty progress data // to indicate there are no more steps to execute. return ""; } function _listOnOpensea( OpenseaAdvancedProposalData memory data, bytes32 conduitKey, uint256 expiry ) private returns (bytes32 orderHash) { if (data.fees.length != data.feeRecipients.length) { revert InvalidFeeRecipients(); } // Create a (basic) Seaport 721 sell order. IOpenseaExchange.Order[] memory orders = new IOpenseaExchange.Order[](1); IOpenseaExchange.Order memory order = orders[0]; IOpenseaExchange.OrderParameters memory orderParams = order.parameters; orderParams.offerer = address(this); orderParams.startTime = block.timestamp; orderParams.endTime = expiry; orderParams.zone = _GLOBALS.getAddress(LibGlobals.GLOBAL_OPENSEA_ZONE); orderParams.orderType = orderParams.zone == address(0) ? IOpenseaExchange.OrderType.FULL_OPEN : IOpenseaExchange.OrderType.FULL_RESTRICTED; orderParams.salt = uint256(bytes32(data.domainHashPrefix)); orderParams.conduitKey = conduitKey; orderParams.totalOriginalConsiderationItems = 1 + data.fees.length; // What we are selling. orderParams.offer = new IOpenseaExchange.OfferItem[](1); IOpenseaExchange.OfferItem memory offer = orderParams.offer[0]; offer.itemType = data.tokenType == TokenType.ERC721 ? IOpenseaExchange.ItemType.ERC721 : IOpenseaExchange.ItemType.ERC1155; offer.token = data.token; offer.identifierOrCriteria = data.tokenId; offer.startAmount = 1; offer.endAmount = 1; // What we want for it. orderParams.consideration = new IOpenseaExchange.ConsiderationItem[](1 + data.fees.length); IOpenseaExchange.ConsiderationItem memory cons = orderParams.consideration[0]; cons.itemType = IOpenseaExchange.ItemType.NATIVE; cons.token = address(0); cons.identifierOrCriteria = 0; cons.startAmount = data.startPrice; cons.endAmount = data.endPrice; cons.recipient = payable(address(this)); for (uint256 i; i < data.fees.length; ++i) { cons = orderParams.consideration[1 + i]; cons.itemType = IOpenseaExchange.ItemType.NATIVE; cons.token = address(0); cons.identifierOrCriteria = 0; cons.startAmount = data.fees[i]; // Adjusted such that the start amount and end amount of fees is // proportional to the start and end price of the listing for // dutch auctions. cons.endAmount = (data.fees[i] * data.endPrice) / data.startPrice; cons.recipient = data.feeRecipients[i]; } orderHash = _getOrderHash(orderParams); // Validate the order on-chain so no signature is required to fill it. assert(SEAPORT.validate(orders)); // Emit an event based on the type of listing. if (data.tokenType == TokenType.ERC721 && data.startPrice == data.endPrice) { emit OpenseaOrderListed( orderParams, orderHash, IERC721(data.token), data.tokenId, data.startPrice, expiry ); } else { emit OpenseaAdvancedOrderListed( orderParams, orderHash, data.token, data.tokenId, data.startPrice, data.endPrice, expiry ); } } function _approveConduit( address token, uint256 tokenId, TokenType tokenType ) private returns (address conduit, bytes32 conduitKey) { // Get the OpenSea conduit key. conduitKey = _GLOBALS.getBytes32(LibGlobals.GLOBAL_OPENSEA_CONDUIT_KEY); // Get conduit. (conduit, ) = CONDUIT_CONTROLLER.getConduit(conduitKey); // Approve OpenSea's conduit to spend our NFT. This should revert if we // do not own the NFT. if (tokenType == TokenType.ERC721) { IERC721(token).approve(conduit, tokenId); } else { IERC1155(token).setApprovalForAll(conduit, true); } } function _getOrderHash( IOpenseaExchange.OrderParameters memory orderParams ) private view returns (bytes32 orderHash) { // `getOrderHash()` wants an `OrderComponents` struct, which is an `OrderParameters` // struct but with the last field (`totalOriginalConsiderationItems`) // replaced with the maker's nonce. Since we (the maker) never increment // our Seaport nonce, it is always 0. // So we temporarily set the `totalOriginalConsiderationItems` field to 0, // force cast the `OrderParameters` into a `OrderComponents` type, call // `getOrderHash()`, and then restore the `totalOriginalConsiderationItems` // field's value before returning. uint256 origTotalOriginalConsiderationItems = orderParams.totalOriginalConsiderationItems; orderParams.totalOriginalConsiderationItems = 0; IOpenseaExchange.OrderComponents memory orderComps; assembly { orderComps := orderParams } orderHash = SEAPORT.getOrderHash(orderComps); orderParams.totalOriginalConsiderationItems = origTotalOriginalConsiderationItems; } function _cleanUpListing( bytes32 orderHash, address conduit, uint256 expiry, address token, uint256 tokenId, TokenType tokenType, uint256 startPrice, uint256 endPrice ) private { (, , uint256 totalFilled, ) = SEAPORT.getOrderStatus(orderHash); if (totalFilled != 0) { // The order was filled before it expired. We no longer have the NFT // and instead we have the ETH it was bought with. // Emit an event based on the type of listing. if (tokenType == TokenType.ERC721 && startPrice == endPrice) { emit OpenseaOrderSold(orderHash, IERC721(token), tokenId, startPrice); } else { emit OpenseaAdvancedOrderSold(orderHash, token, tokenId, startPrice, endPrice); } } else if (expiry <= block.timestamp) { // The order expired before it was filled. We retain the NFT. // Revoke Seaport approval. if (tokenType == TokenType.ERC721) { IERC721(token).approve(address(0), tokenId); } else { IERC1155(token).setApprovalForAll(conduit, false); } emit OpenseaOrderExpired(orderHash, token, tokenId, expiry); } else { // The order hasn't been bought and is still active. revert OpenseaOrderStillActiveError(orderHash, token, tokenId, expiry); } } }
// SPDX-License-Identifier: GPL-3.0 pragma solidity 0.8.17; import "./ListOnOpenseaAdvancedProposal.sol"; // Implements proposal listing an NFT on OpenSea (Seaport). Inherited by the `ProposalExecutionEngine`. // This contract will be delegatecall'ed into by `Party` proxy instances. abstract contract ListOnOpenseaProposal is OpenseaHelpers { // ABI-encoded `proposalData` passed into execute. struct OpenseaProposalData { // The price (in ETH) to sell the NFT. uint256 listPrice; // How long the listing is valid for. uint40 duration; // The NFT token contract. IERC721 token; // the NFT token ID. uint256 tokenId; // Fees the taker must pay when filling the listing. uint256[] fees; // Respective recipients for each fee. address payable[] feeRecipients; // The first 4 bytes of the hash of a domain to attribute the listing to. // https://opensea.notion.site/opensea/Proposal-for-Seaport-Order-Attributions-via-Arbitrary-Domain-Hash-d0ad30b994ba48278c6e922983175285 bytes4 domainHashPrefix; } // Try to create a listing (ultimately) on OpenSea (Seaport). // Creates a listing on Zora auction house for list price first. When that ends, // calling this function again will list on OpenSea. When that ends, // calling this function again will cancel the listing. function _executeListOnOpensea( IProposalExecutionEngine.ExecuteProposalParams memory params ) internal returns (bytes memory nextProgressData) { OpenseaProposalData memory data = abi.decode(params.proposalData, (OpenseaProposalData)); return _executeAdvancedOpenseaProposal( params, ListOnOpenseaAdvancedProposal.OpenseaAdvancedProposalData({ startPrice: data.listPrice, endPrice: data.listPrice, duration: data.duration, tokenType: ListOnOpenseaAdvancedProposal.TokenType.ERC721, token: address(data.token), tokenId: data.tokenId, fees: data.fees, feeRecipients: data.feeRecipients, domainHashPrefix: data.domainHashPrefix }) ); } }
// SPDX-License-Identifier: GPL-3.0 pragma solidity 0.8.17; import "../globals/IGlobals.sol"; import "../globals/LibGlobals.sol"; import "../tokens/IERC721.sol"; import "../utils/LibRawResult.sol"; import "../utils/LibSafeERC721.sol"; import "../utils/LibSafeCast.sol"; import "../vendor/markets/IZoraAuctionHouse.sol"; import "./IProposalExecutionEngine.sol"; import "./ZoraHelpers.sol"; // Implements proposals auctioning an NFT on Zora. Inherited by the `ProposalExecutionEngine`. // This contract will be delegatecall'ed into by `Party` proxy instances. contract ListOnZoraProposal is ZoraHelpers { using LibRawResult for bytes; using LibSafeERC721 for IERC721; using LibSafeCast for uint256; enum ZoraStep { // Proposal has not been executed yet and should be listed on Zora. None, // Proposal was previously executed and the NFT is already listed on Zora. ListedOnZora } // ABI-encoded `proposalData` passed into execute. struct ZoraProposalData { // The minimum bid (ETH) for the NFT. uint256 listPrice; // How long before the auction can be cancelled if no one bids. uint40 timeout; // How long the auction lasts once a person bids on it. uint40 duration; // The token contract of the NFT being listed. IERC721 token; // The token ID of the NFT being listed. uint256 tokenId; } error ZoraListingNotExpired(uint256 auctionId, uint40 expiry); event ZoraAuctionCreated( uint256 auctionId, IERC721 token, uint256 tokenId, uint256 startingPrice, uint40 duration, uint40 timeoutTime ); event ZoraAuctionExpired(uint256 auctionId, uint256 expiry); event ZoraAuctionSold(uint256 auctionId); event ZoraAuctionFailed(uint256 auctionId); // keccak256(abi.encodeWithSignature('Error(string)', "Auction hasn't begun")) bytes32 internal constant AUCTION_HASNT_BEGUN_ERROR_HASH = 0x54a53788b7942d79bb6fcd40012c5e867208839fa1607e1f245558ee354e9565; // keccak256(abi.encodeWithSignature('Error(string)', "Auction doesn't exit")) bytes32 internal constant AUCTION_DOESNT_EXIST_ERROR_HASH = 0x474ba0184a7cd5de777156a56f3859150719340a6974b6ee50f05c58139f4dc2; /// @notice Zora auction house contract. IZoraAuctionHouse public immutable ZORA; // The `Globals` contract storing global configuration values. This contract // is immutable and it’s address will never change. IGlobals private immutable _GLOBALS; // Set immutables. constructor(IGlobals globals, IZoraAuctionHouse zoraAuctionHouse) { ZORA = zoraAuctionHouse; _GLOBALS = globals; } // Auction an NFT we hold on Zora. // Calling this the first time will create a Zora auction. // Calling this the second time will either cancel or finalize the auction. function _executeListOnZora( IProposalExecutionEngine.ExecuteProposalParams memory params ) internal returns (bytes memory nextProgressData) { ZoraProposalData memory data = abi.decode(params.proposalData, (ZoraProposalData)); // If there is progressData passed in, we're on the first step, // otherwise parse the first word of the progressData as the current step. ZoraStep step = params.progressData.length == 0 ? ZoraStep.None : abi.decode(params.progressData, (ZoraStep)); if (step == ZoraStep.None) { // Proposal hasn't executed yet. { // Clamp the Zora auction duration to the global minimum and maximum. uint40 minDuration = uint40( _GLOBALS.getUint256(LibGlobals.GLOBAL_ZORA_MIN_AUCTION_DURATION) ); uint40 maxDuration = uint40( _GLOBALS.getUint256(LibGlobals.GLOBAL_ZORA_MAX_AUCTION_DURATION) ); if (minDuration != 0 && data.duration < minDuration) { data.duration = minDuration; } else if (maxDuration != 0 && data.duration > maxDuration) { data.duration = maxDuration; } // Clamp the Zora auction timeout to the global maximum. uint40 maxTimeout = uint40( _GLOBALS.getUint256(LibGlobals.GLOBAL_ZORA_MAX_AUCTION_TIMEOUT) ); if (maxTimeout != 0 && data.timeout > maxTimeout) { data.timeout = maxTimeout; } } // Create a Zora auction for the NFT. uint256 auctionId = _createZoraAuction( data.listPrice, data.timeout, data.duration, data.token, data.tokenId ); return abi.encode( ZoraStep.ListedOnZora, ZoraProgressData({ auctionId: auctionId, minExpiry: (block.timestamp + data.timeout).safeCastUint256ToUint40() }) ); } assert(step == ZoraStep.ListedOnZora); (, ZoraProgressData memory pd) = abi.decode( params.progressData, (ZoraStep, ZoraProgressData) ); _settleZoraAuction(pd.auctionId, pd.minExpiry, data.token, data.tokenId); // Nothing left to do. return ""; } // Transfer and create a Zora auction for the `token` + `tokenId`. function _createZoraAuction( // The minimum bid. uint256 listPrice, // How long the auction must wait for the first bid. uint40 timeout, // How long the auction will run for once a bid has been placed. uint40 duration, IERC721 token, uint256 tokenId ) internal override returns (uint256 auctionId) { token.approve(address(ZORA), tokenId); auctionId = ZORA.createAuction( tokenId, token, duration, listPrice, payable(address(0)), 0, IERC20(address(0)) // Indicates ETH sale ); emit ZoraAuctionCreated( auctionId, token, tokenId, listPrice, duration, uint40(block.timestamp + timeout) ); } // Either cancel or finalize a Zora auction. function _settleZoraAuction( uint256 auctionId, uint40 minExpiry, IERC721 token, uint256 tokenId ) internal override returns (ZoraAuctionStatus statusCode) { // Getting the state of an auction is super expensive so it seems // cheaper to just let `endAuction()` fail and react to the error. try ZORA.endAuction(auctionId) { // Check whether auction cancelled due to a failed transfer during // settlement by seeing if we now possess the NFT. if (token.safeOwnerOf(tokenId) == address(this)) { emit ZoraAuctionFailed(auctionId); return ZoraAuctionStatus.Cancelled; } } catch (bytes memory errData) { bytes32 errHash = keccak256(errData); if (errHash == AUCTION_HASNT_BEGUN_ERROR_HASH) { // No bids placed. // Cancel if we're past the timeout. if (minExpiry > uint40(block.timestamp)) { revert ZoraListingNotExpired(auctionId, minExpiry); } ZORA.cancelAuction(auctionId); emit ZoraAuctionExpired(auctionId, minExpiry); return ZoraAuctionStatus.Expired; } else if (errHash != AUCTION_DOESNT_EXIST_ERROR_HASH) { // Otherwise, we should get an auction doesn't exist error, // because someone else must have called `endAuction()`. // If we didn't then something is wrong, so revert. errData.rawRevert(); } // Already ended by someone else. Nothing to do. } emit ZoraAuctionSold(auctionId); return ZoraAuctionStatus.Sold; } }
// SPDX-License-Identifier: GPL-3.0 pragma solidity 0.8.17; import "./ListOnOpenseaAdvancedProposal.sol"; import "./IProposalExecutionEngine.sol"; import "./vendor/IOpenseaExchange.sol"; // Abstract Opensea interaction functions. abstract contract OpenseaHelpers { function _executeAdvancedOpenseaProposal( IProposalExecutionEngine.ExecuteProposalParams memory params, ListOnOpenseaAdvancedProposal.OpenseaAdvancedProposalData memory data ) internal virtual returns (bytes memory nextProgressData); }
// 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 } } }
// SPDX-License-Identifier: GPL-3.0 pragma solidity 0.8.17; import "../tokens/IERC721.sol"; // Abstract Zora interaction functions. // Used by both `ListOnZoraProposal` and `ListOnOpenseaProposal`. abstract contract ZoraHelpers { // ABI-encoded `progressData` passed into execute in the `ListedOnZora` step. struct ZoraProgressData { // Auction ID. uint256 auctionId; // The minimum timestamp when we can cancel the auction if no one bids. uint40 minExpiry; } enum ZoraAuctionStatus { Sold, Expired, Cancelled } // Transfer and create a Zora auction for the token + tokenId. function _createZoraAuction( // The minimum bid. uint256 listPrice, // How long the auction must wait for the first bid. uint40 timeout, // How long the auction will run for once a bid has been placed. uint40 duration, IERC721 token, uint256 tokenId ) internal virtual returns (uint256 auctionId); // Either cancel or finalize a Zora auction. function _settleZoraAuction( uint256 auctionId, uint40 minExpiry, IERC721 token, uint256 tokenId ) internal virtual returns (ZoraAuctionStatus statusCode); }
// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8; import "../../tokens/IERC20.sol"; import "../../tokens/IERC721.sol"; /// @dev FractionalVaultFactory interface from /// https://github.com/fractional-company/contracts/blob/643bb669ad71aac8d1b11f0300c9bb0dec494daa/src/ERC721VaultFactory.sol interface IFractionalV1VaultFactory { function vaultCount() external view returns (uint256 count); function vaults(uint256 vaultId) external view returns (IFractionalV1Vault vault); function mint( string calldata name, string calldata symbol, IERC721 token, uint256 tokenId, uint256 supply, uint256 listPrice, uint256 fee ) external returns (uint256 vaultId); } /// @dev ERC721TokenVault interface from /// https://github.com/fractional-company/contracts/blob/d4faa2dddf010d12b87eae8054f485656c8ed14b/src/ERC721TokenVault.sol interface IFractionalV1Vault is IERC20 { function curator() external view returns (address curator_); function auctionEnd() external view returns (uint256); function reservePrice() external view returns (uint256); function livePrice() external view returns (uint256); function winning() external view returns (address); function updateCurator(address curator_) external; function updateUserPrice(uint256) external; function start() external payable; function bid() external payable; function end() external; function redeem() external; function cash() external; }
// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8; interface IOpenseaConduitController { function getKey(address conduit) external view returns (bytes32 conduitKey); function getConduit(bytes32 conduitKey) external view returns (address conduit, bool exists); }
// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8; interface IOpenseaExchange { error InvalidTime(); enum OrderType { FULL_OPEN, PARTIAL_OPEN, FULL_RESTRICTED, PARTIAL_RESTRICTED } enum ItemType { NATIVE, ERC20, ERC721, ERC1155, ERC721_WITH_CRITERIA, ERC1155_WITH_CRITERIA } enum BasicOrderType { ETH_TO_ERC721_FULL_OPEN, ETH_TO_ERC721_PARTIAL_OPEN, ETH_TO_ERC721_FULL_RESTRICTED, ETH_TO_ERC721_PARTIAL_RESTRICTED, ETH_TO_ERC1155_FULL_OPEN, ETH_TO_ERC1155_PARTIAL_OPEN, ETH_TO_ERC1155_FULL_RESTRICTED, ETH_TO_ERC1155_PARTIAL_RESTRICTED, ERC20_TO_ERC721_FULL_OPEN, ERC20_TO_ERC721_PARTIAL_OPEN, ERC20_TO_ERC721_FULL_RESTRICTED, ERC20_TO_ERC721_PARTIAL_RESTRICTED, ERC20_TO_ERC1155_FULL_OPEN, ERC20_TO_ERC1155_PARTIAL_OPEN, ERC20_TO_ERC1155_FULL_RESTRICTED, ERC20_TO_ERC1155_PARTIAL_RESTRICTED, ERC721_TO_ERC20_FULL_OPEN, ERC721_TO_ERC20_PARTIAL_OPEN, ERC721_TO_ERC20_FULL_RESTRICTED, ERC721_TO_ERC20_PARTIAL_RESTRICTED, ERC1155_TO_ERC20_FULL_OPEN, ERC1155_TO_ERC20_PARTIAL_OPEN, ERC1155_TO_ERC20_FULL_RESTRICTED, ERC1155_TO_ERC20_PARTIAL_RESTRICTED } struct OfferItem { ItemType itemType; address token; uint256 identifierOrCriteria; uint256 startAmount; uint256 endAmount; } struct ConsiderationItem { ItemType itemType; address token; uint256 identifierOrCriteria; uint256 startAmount; uint256 endAmount; address payable recipient; } struct OrderParameters { address offerer; address zone; OfferItem[] offer; ConsiderationItem[] consideration; OrderType orderType; uint256 startTime; uint256 endTime; bytes32 zoneHash; uint256 salt; bytes32 conduitKey; uint256 totalOriginalConsiderationItems; } struct Order { OrderParameters parameters; bytes signature; } struct OrderComponents { address offerer; address zone; OfferItem[] offer; ConsiderationItem[] consideration; OrderType orderType; uint256 startTime; uint256 endTime; bytes32 zoneHash; uint256 salt; bytes32 conduitKey; uint256 nonce; } struct AdditionalRecipient { uint256 amount; address payable recipient; } struct BasicOrderParameters { address considerationToken; uint256 considerationIdentifier; uint256 considerationAmount; address payable offerer; address zone; address offerToken; uint256 offerIdentifier; uint256 offerAmount; BasicOrderType basicOrderType; uint256 startTime; uint256 endTime; bytes32 zoneHash; uint256 salt; bytes32 offererConduitKey; bytes32 fulfillerConduitKey; uint256 totalOriginalAdditionalRecipients; AdditionalRecipient[] additionalRecipients; bytes signature; } function cancel(OrderComponents[] calldata orders) external returns (bool cancelled); function validate(Order[] calldata orders) external returns (bool validated); function fulfillBasicOrder( BasicOrderParameters calldata parameters ) external payable returns (bool fulfilled); function fulfillOrder( Order calldata order, bytes32 fulfillerConduitKey ) external payable returns (bool fulfilled); function getOrderStatus( bytes32 orderHash ) external view returns (bool isValidated, bool isCancelled, uint256 totalFilled, uint256 totalSize); function getOrderHash(OrderComponents calldata order) external view returns (bytes32 orderHash); function getNonce(address offerer) external view returns (uint256 nonce); }
// 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="M188 444.3h2.4l2.6 8.2 2.7-8.2h2.3l-3.7 10.7h-2.8l-3.5-10.7zm10.5 5.3c0-3.2 2.2-5.6 5.3-5.6 3.1 0 5.3 2.3 5.3 5.6 0 3.2-2.2 5.5-5.3 5.5-3.1.1-5.3-2.2-5.3-5.5zm5.3 3.5c1.8 0 3-1.3 3-3.4 0-2.1-1.1-3.5-3-3.5s-3 1.3-3 3.5c0 2.1 1.1 3.4 3 3.4zm8.7-6.7h-3.1v-2.1h8.4v2.1h-3.1v8.6h-2.2v-8.6zm6.9-2.1h2.2V455h-2.2v-10.7zm4.3 0h2.9l4 8.2v-8.2h2.1V455h-2.9l-4-8.2v8.2h-2.1v-10.7zm10.6 5.4c0-3.4 2.3-5.6 6-5.6 1.2 0 2.3.2 3.1.6v2.3c-.9-.6-1.9-.8-3.1-.8-2.4 0-3.8 1.3-3.8 3.5 0 2.1 1.3 3.4 3.5 3.4.5 0 .9-.1 1.3-.2v-2.2h-2.2v-1.9h4.3v5.6c-1 .5-2.2.8-3.4.8-3.5 0-5.7-2.2-5.7-5.5zm15.1-5.4h4.3c2.3 0 3.7 1.3 3.7 3.5s-1.4 3.5-3.7 3.5h-2.1v3.7h-2.2v-10.7zm4.1 5c1.1 0 1.6-.5 1.6-1.5s-.5-1.5-1.6-1.5h-1.9v2.9h1.9zm4.8.3c0-3.2 2.2-5.6 5.3-5.6 3.1 0 5.3 2.3 5.3 5.6 0 3.2-2.2 5.5-5.3 5.5-3.1.1-5.3-2.2-5.3-5.5zm5.3 3.5c1.8 0 3-1.3 3-3.4 0-2.1-1.1-3.5-3-3.5s-3 1.3-3 3.5c0 2.1 1.1 3.4 3 3.4zm5.8-8.8h2.3l1.7 7.8 1.9-7.8h2.4l1.8 7.8 1.8-7.8h2.3l-2.7 10.7h-2.5l-1.9-8.2-1.8 8.2h-2.5l-2.8-10.7zm15.4 0h6.9v2.1H287v2.2h4.5v2.1H287v2.3h4.9v2.1h-7v-10.8zm9 0h4.5c2 0 3.3 1.3 3.3 3.2 0 1.9-1.2 3.1-3 3.2l3.5 4.3h-2.7l-3.5-4.4v4.4h-2.1v-10.7zm4.1 4.8c1 0 1.5-.5 1.5-1.4 0-.9-.6-1.4-1.5-1.4h-2v2.9h2zM30 444.3h4.3c3 0 5.2 2.1 5.2 5.4s-2.1 5.4-5.2 5.4H30v-10.8zm4 8.6c2.1 0 3.2-1.2 3.2-3.2s-1.2-3.3-3.2-3.3h-1.8v6.5H34zm7.7-8.6h2.2V455h-2.2v-10.7zm4.8 10V452c1 .7 2.1 1.1 3.2 1.1s1.7-.5 1.7-1.2-.4-1-1.2-1.2l-1.2-.3c-1.8-.5-2.7-1.5-2.7-3.1 0-2 1.5-3.2 3.9-3.2 1 0 2.1.2 2.9.7v2.3c-.9-.6-1.9-.8-3-.8-.9 0-1.6.4-1.6 1.1 0 .6.4.9 1.2 1.1l1.3.4c1.8.5 2.6 1.4 2.6 3.1 0 2.1-1.5 3.4-3.8 3.4-1.1-.2-2.3-.5-3.3-1.1zm12-7.9h-3.1v-2.1h8.4v2.1h-3.1v8.6h-2.2v-8.6zm7.5-2.1h4.5c2 0 3.3 1.3 3.3 3.2 0 1.9-1.2 3.1-3 3.2l3.5 4.3h-2.7l-3.5-4.4v4.4H66v-10.7zm4.1 4.8c1 0 1.5-.5 1.5-1.4s-.6-1.4-1.5-1.4h-2v2.9h2zm6.1-4.8h2.2V455h-2.2v-10.7zm5 0h4.5c2 0 3.2 1.1 3.2 2.8 0 1.1-.5 1.9-1.4 2.3 1.1.3 1.8 1.3 1.8 2.5 0 1.9-1.3 3.1-3.5 3.1h-4.6v-10.7zm4.2 4.4c.9 0 1.4-.5 1.4-1.3s-.5-1.3-1.4-1.3h-2.1v2.5l2.1.1zm.3 4.4c.9 0 1.5-.5 1.5-1.3s-.6-1.3-1.5-1.3h-2.4v2.6h2.4zm5.7-2.5v-6.3h2.2v6.3c0 1.6.9 2.5 2.3 2.5s2.3-.9 2.3-2.5v-6.3h2.2v6.3c0 2.9-1.7 4.6-4.5 4.6s-4.6-1.7-4.5-4.6zm14.2-4.2h-3.1v-2.1h8.4v2.1h-3.1v8.6h-2.2v-8.6zm7.5-2.1h2.2V455h-2.2v-10.7zm4.5 5.3c0-3.2 2.2-5.6 5.3-5.6s5.3 2.3 5.3 5.6-2.2 5.5-5.3 5.5-5.3-2.2-5.3-5.5zm5.3 3.5c1.8 0 3-1.3 3-3.5s-1.2-3.5-3-3.5-3 1.3-3 3.5 1.1 3.5 3 3.5zm7.5-8.8h2.9l4 8.2v-8.2h2.1V455h-2.9l-4-8.2v8.2h-2.1v-10.7zm11.7 10V452c1 .7 2.1 1.1 3.2 1.1s1.7-.5 1.7-1.2-.4-1-1.2-1.2l-1.2-.3c-1.8-.5-2.6-1.5-2.6-3.1 0-2 1.5-3.2 3.9-3.2 1.1 0 2.1.2 2.9.7v2.3c-.9-.6-1.9-.8-3-.8-.9 0-1.6.4-1.6 1.1 0 .6.4.9 1.2 1.1l1.3.4c1.8.5 2.6 1.4 2.6 3.1 0 2.1-1.5 3.4-3.8 3.4a9.7 9.7 0 0 1-3.4-1.1zM30 259.3h4.3c2.2 0 3.7 1.3 3.7 3.5s-1.4 3.5-3.7 3.5h-2.1v3.7H30v-10.7zm4.1 5c1.1 0 1.6-.5 1.6-1.5s-.5-1.5-1.6-1.5h-1.9v2.9h1.9zm6.1-5h4.5c2 0 3.3 1.3 3.3 3.2 0 1.9-1.2 3.1-3 3.2l3.5 4.3h-2.7l-3.5-4.4v4.4h-2.1v-10.7zm4.1 4.8c1 0 1.5-.5 1.5-1.4s-.6-1.4-1.5-1.4h-2v2.9h2zm5.4.5c0-3.2 2.2-5.6 5.3-5.6s5.3 2.3 5.3 5.6-2.2 5.5-5.3 5.5-5.3-2.2-5.3-5.5zm5.3 3.5c1.8 0 3-1.3 3-3.5s-1.2-3.5-3-3.5-3 1.3-3 3.5 1.1 3.5 3 3.5zm7.6-8.8h4.3c2.2 0 3.7 1.3 3.7 3.5s-1.4 3.5-3.7 3.5h-2.1v3.7h-2.2v-10.7zm4.1 5c1.1 0 1.6-.5 1.6-1.5s-.6-1.5-1.6-1.5h-1.9v2.9h1.9zm5.4.4c0-3.2 2.2-5.6 5.3-5.6s5.3 2.3 5.3 5.6-2.2 5.5-5.3 5.5-5.3-2.3-5.3-5.5zm5.4 3.4c1.8 0 3-1.3 3-3.5s-1.2-3.5-3-3.5-3 1.3-3 3.5 1.1 3.5 3 3.5zm7.2 1.2V267c1 .7 2.1 1.1 3.2 1.1s1.7-.5 1.7-1.2-.4-1-1.2-1.2l-1.2-.3c-1.8-.5-2.7-1.5-2.7-3.1 0-2 1.5-3.2 3.9-3.2 1.1 0 2.1.2 2.9.7v2.3c-.9-.6-1.9-.8-3-.8-.9 0-1.6.4-1.6 1.1 0 .6.4.9 1.2 1.1l1.3.4c1.8.5 2.6 1.4 2.6 3.1 0 2.1-1.5 3.4-3.8 3.4-1.1-.2-2.3-.5-3.3-1.1zm12.2-10h2.8l3.7 10.7h-2.3l-.8-2.5h-4l-.8 2.5h-2.2l3.6-10.7zm2.8 6.3-1.4-4.2-1.4 4.2h2.8zm5.7-6.3h2.2v8.6h4.7v2.1h-6.9v-10.7zm9.1 10V267c1 .7 2.1 1.1 3.2 1.1s1.7-.5 1.7-1.2-.4-1-1.2-1.2l-1.2-.3c-1.8-.5-2.7-1.5-2.7-3.1 0-2 1.5-3.2 3.9-3.2 1.1 0 2.1.2 2.9.7v2.3c-.9-.6-1.9-.8-3-.8-.9 0-1.6.4-1.6 1.1 0 .6.4.9 1.2 1.1l1.3.4c1.8.5 2.6 1.4 2.6 3.1 0 2.1-1.5 3.4-3.8 3.4-1.1-.2-2.3-.5-3.3-1.1zm-84.5-70h2.9l4 8.2v-8.2H39V210h-2.9l-4-8.2v8.2H30v-10.7zm14.7 0h2.8l3.7 10.7h-2.3l-.8-2.6h-4l-.8 2.6H41l3.7-10.7zm2.8 6.2-1.4-4.2-1.4 4.2h2.8zm5.7-6.2h3.3l2.5 8.2 2.5-8.2h3.3V210h-2v-8.6L60 210h-2.1l-2.7-8.5v8.5h-2v-10.7zm14.4 0h6.9v2.1h-4.8v2.2h4.4v2.1h-4.4v2.3h4.9v2.1h-7v-10.8z" /><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; } }
// 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 pure virtual override returns (bool) { return super.supportsInterface(interfaceId) || interfaceId == type(ERC1155TokenReceiverBase).interfaceId; } }
// 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; } }
// 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); }
// 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); }
// 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); }
// 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); }
// 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 pure virtual returns (bool) { return interfaceId == this.supportsInterface.selector; } }
// 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() { if (address(this).code.length != 0) { revert OnlyConstructorError(); } _; } }
// SPDX-License-Identifier: GPL-3.0 pragma solidity 0.8.17; library LibAddress { error EthTransferFailed(address receiver, bytes errData); // Transfer ETH with full gas stipend. function transferEth(address payable receiver, uint256 amount) internal { if (amount == 0) return; (bool s, bytes memory r) = receiver.call{ value: amount }(""); if (!s) { revert EthTransferFailed(receiver, r); } } }
// 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); } }
// 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)) } } }
// 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); } }
// SPDX-License-Identifier: GPL-3.0 pragma solidity 0.8.17; import "../tokens/IERC721.sol"; import "./LibRawResult.sol"; library LibSafeERC721 { using LibRawResult for bytes; // Call `IERC721.ownerOf()` without reverting and return `address(0)` if: // - `tokenID` does not exist. // - `token` is an EOA // - `token` is an empty contract // - `token` is a "bad" implementation of ERC721 that returns nothing for // `ownerOf()` function safeOwnerOf(IERC721 token, uint256 tokenId) internal view returns (address owner) { (bool s, bytes memory r) = address(token).staticcall( abi.encodeCall(token.ownerOf, (tokenId)) ); if (!s || r.length < 32) { return address(0); } return abi.decode(r, (address)); } }
// 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(); } } } }
// 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(); } } }
// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8; import "../../tokens/IERC721.sol"; import "../../tokens/IERC20.sol"; // Based on https://etherscan.io/address/0xe468ce99444174bd3bbbed09209577d25d1ad673#code interface IZoraAuctionHouse { struct Auction { // ID for the ERC721 token uint256 tokenId; // Address for the ERC721 contract IERC721 tokenContract; // Whether or not the auction curator has approved the auction to start bool approved; // The current highest bid amount uint256 amount; // The length of time to run the auction for, after the first bid was made uint256 duration; // The time of the first bid uint256 firstBidTime; // The minimum price of the first bid uint256 reservePrice; // The sale percentage to send to the curator uint8 curatorFeePercentage; // The address that should receive the funds once the NFT is sold. address tokenOwner; // The address of the current highest bid address payable bidder; // The address of the auction's curator. // The curator can reject or approve an auction address payable curator; // The address of the ERC-20 currency to run the auction with. // If set to 0x0, the auction will be run in ETH IERC20 auctionCurrency; } event AuctionCreated( uint256 indexed auctionId, uint256 indexed tokenId, address indexed tokenContract, uint256 duration, uint256 reservePrice, address tokenOwner, address curator, uint8 curatorFeePercentage, address auctionCurrency ); function createAuction( uint256 tokenId, IERC721 tokenContract, uint256 duration, uint256 reservePrice, address payable curator, uint8 curatorFeePercentages, IERC20 auctionCurrency ) external returns (uint256); function createBid(uint256 auctionId, uint256 amount) external payable; function endAuction(uint256 auctionId) external; function cancelAuction(uint256 auctionId) external; function auctions(uint256 auctionId) external view returns (Auction memory auction); function timeBuffer() external view returns (uint256); function minBidIncrementPercentage() external view returns (uint8); }
// 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; } }
// 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 /* view */) public 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; } }
// 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); }
// 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); }
// 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. ); /// @solidity memory-safe-assembly 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) { /// @solidity memory-safe-assembly 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) } } }
{ "remappings": [ "ds-test/=lib/forge-std/lib/ds-test/src/", "erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/", "forge-std/=lib/forge-std/src/", "openzeppelin-contracts/=lib/openzeppelin-contracts/", "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
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"contract IGlobals","name":"globals","type":"address"},{"internalType":"contract IOpenseaExchange","name":"seaport","type":"address"},{"internalType":"contract IOpenseaConduitController","name":"seaportConduitController","type":"address"},{"internalType":"contract IZoraAuctionHouse","name":"zoraAuctionHouse","type":"address"},{"internalType":"contract IFractionalV1VaultFactory","name":"fractionalVaultFactory","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"bytes","name":"revertData","type":"bytes"}],"name":"ArbitraryCallFailedError","type":"error"},{"inputs":[{"internalType":"address","name":"target","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"CallProhibitedError","type":"error"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"},{"internalType":"bytes","name":"errData","type":"bytes"}],"name":"EthTransferFailed","type":"error"},{"inputs":[{"internalType":"uint256","name":"callDataLength","type":"uint256"}],"name":"InvalidApprovalCallLength","type":"error"},{"inputs":[],"name":"InvalidFeeRecipients","type":"error"},{"inputs":[],"name":"MalformedProposalDataError","type":"error"},{"inputs":[{"internalType":"uint256","name":"callValue","type":"uint256"},{"internalType":"uint256","name":"ethAvailable","type":"uint256"}],"name":"NotEnoughEthAttachedError","type":"error"},{"inputs":[],"name":"OnlyConstructorError","type":"error"},{"inputs":[],"name":"OnlyDelegateCallError","type":"error"},{"inputs":[{"internalType":"bytes32","name":"orderHash","type":"bytes32"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"expiry","type":"uint256"}],"name":"OpenseaOrderStillActiveError","type":"error"},{"inputs":[{"internalType":"contract IERC721","name":"token","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"PreciousLostError","type":"error"},{"inputs":[{"internalType":"uint256","name":"proposalId","type":"uint256"},{"internalType":"uint256","name":"currentInProgressProposalId","type":"uint256"}],"name":"ProposalExecutionBlockedError","type":"error"},{"inputs":[{"internalType":"uint256","name":"proposalId","type":"uint256"}],"name":"ProposalNotInProgressError","type":"error"},{"inputs":[{"internalType":"bytes32","name":"actualProgressDataHash","type":"bytes32"},{"internalType":"bytes32","name":"expectedProgressDataHash","type":"bytes32"}],"name":"ProposalProgressDataInvalidError","type":"error"},{"inputs":[{"internalType":"uint256","name":"u256","type":"uint256"}],"name":"Uint256ToUint40CastOutOfRangeError","type":"error"},{"inputs":[{"internalType":"uint256","name":"idx","type":"uint256"},{"internalType":"bytes32","name":"resultHash","type":"bytes32"},{"internalType":"bytes32","name":"expectedResultHash","type":"bytes32"}],"name":"UnexpectedCallResultHashError","type":"error"},{"inputs":[{"internalType":"contract IProposalExecutionEngine","name":"actualImpl","type":"address"},{"internalType":"contract IProposalExecutionEngine","name":"expectedImpl","type":"address"}],"name":"UnexpectedProposalEngineImplementationError","type":"error"},{"inputs":[{"internalType":"uint32","name":"proposalType","type":"uint32"}],"name":"UnsupportedProposalTypeError","type":"error"},{"inputs":[],"name":"ZeroProposalIdError","type":"error"},{"inputs":[{"internalType":"uint256","name":"auctionId","type":"uint256"},{"internalType":"uint40","name":"expiry","type":"uint40"}],"name":"ZoraListingNotExpired","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"proposalId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"idx","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"count","type":"uint256"}],"name":"ArbitraryCallExecuted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"contract IERC721","name":"token","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"vaultId","type":"uint256"},{"indexed":false,"internalType":"contract IERC20","name":"vault","type":"address"}],"name":"FractionalV1VaultCreated","type":"event"},{"anonymous":false,"inputs":[{"components":[{"internalType":"address","name":"offerer","type":"address"},{"internalType":"address","name":"zone","type":"address"},{"components":[{"internalType":"enum IOpenseaExchange.ItemType","name":"itemType","type":"uint8"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"identifierOrCriteria","type":"uint256"},{"internalType":"uint256","name":"startAmount","type":"uint256"},{"internalType":"uint256","name":"endAmount","type":"uint256"}],"internalType":"struct IOpenseaExchange.OfferItem[]","name":"offer","type":"tuple[]"},{"components":[{"internalType":"enum IOpenseaExchange.ItemType","name":"itemType","type":"uint8"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"identifierOrCriteria","type":"uint256"},{"internalType":"uint256","name":"startAmount","type":"uint256"},{"internalType":"uint256","name":"endAmount","type":"uint256"},{"internalType":"address payable","name":"recipient","type":"address"}],"internalType":"struct IOpenseaExchange.ConsiderationItem[]","name":"consideration","type":"tuple[]"},{"internalType":"enum IOpenseaExchange.OrderType","name":"orderType","type":"uint8"},{"internalType":"uint256","name":"startTime","type":"uint256"},{"internalType":"uint256","name":"endTime","type":"uint256"},{"internalType":"bytes32","name":"zoneHash","type":"bytes32"},{"internalType":"uint256","name":"salt","type":"uint256"},{"internalType":"bytes32","name":"conduitKey","type":"bytes32"},{"internalType":"uint256","name":"totalOriginalConsiderationItems","type":"uint256"}],"indexed":false,"internalType":"struct IOpenseaExchange.OrderParameters","name":"orderParams","type":"tuple"},{"indexed":false,"internalType":"bytes32","name":"orderHash","type":"bytes32"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"startPrice","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"endPrice","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"expiry","type":"uint256"}],"name":"OpenseaAdvancedOrderListed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"orderHash","type":"bytes32"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"startPrice","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"endPrice","type":"uint256"}],"name":"OpenseaAdvancedOrderSold","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"orderHash","type":"bytes32"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"expiry","type":"uint256"}],"name":"OpenseaOrderExpired","type":"event"},{"anonymous":false,"inputs":[{"components":[{"internalType":"address","name":"offerer","type":"address"},{"internalType":"address","name":"zone","type":"address"},{"components":[{"internalType":"enum IOpenseaExchange.ItemType","name":"itemType","type":"uint8"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"identifierOrCriteria","type":"uint256"},{"internalType":"uint256","name":"startAmount","type":"uint256"},{"internalType":"uint256","name":"endAmount","type":"uint256"}],"internalType":"struct IOpenseaExchange.OfferItem[]","name":"offer","type":"tuple[]"},{"components":[{"internalType":"enum IOpenseaExchange.ItemType","name":"itemType","type":"uint8"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"identifierOrCriteria","type":"uint256"},{"internalType":"uint256","name":"startAmount","type":"uint256"},{"internalType":"uint256","name":"endAmount","type":"uint256"},{"internalType":"address payable","name":"recipient","type":"address"}],"internalType":"struct IOpenseaExchange.ConsiderationItem[]","name":"consideration","type":"tuple[]"},{"internalType":"enum IOpenseaExchange.OrderType","name":"orderType","type":"uint8"},{"internalType":"uint256","name":"startTime","type":"uint256"},{"internalType":"uint256","name":"endTime","type":"uint256"},{"internalType":"bytes32","name":"zoneHash","type":"bytes32"},{"internalType":"uint256","name":"salt","type":"uint256"},{"internalType":"bytes32","name":"conduitKey","type":"bytes32"},{"internalType":"uint256","name":"totalOriginalConsiderationItems","type":"uint256"}],"indexed":false,"internalType":"struct IOpenseaExchange.OrderParameters","name":"orderParams","type":"tuple"},{"indexed":false,"internalType":"bytes32","name":"orderHash","type":"bytes32"},{"indexed":false,"internalType":"contract IERC721","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"listPrice","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"expiry","type":"uint256"}],"name":"OpenseaOrderListed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"orderHash","type":"bytes32"},{"indexed":false,"internalType":"contract IERC721","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"listPrice","type":"uint256"}],"name":"OpenseaOrderSold","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldImpl","type":"address"},{"indexed":false,"internalType":"address","name":"newImpl","type":"address"}],"name":"ProposalEngineImplementationUpgraded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"auctionId","type":"uint256"},{"indexed":false,"internalType":"contract IERC721","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"startingPrice","type":"uint256"},{"indexed":false,"internalType":"uint40","name":"duration","type":"uint40"},{"indexed":false,"internalType":"uint40","name":"timeoutTime","type":"uint40"}],"name":"ZoraAuctionCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"auctionId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"expiry","type":"uint256"}],"name":"ZoraAuctionExpired","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"auctionId","type":"uint256"}],"name":"ZoraAuctionFailed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"auctionId","type":"uint256"}],"name":"ZoraAuctionSold","type":"event"},{"inputs":[],"name":"CONDUIT_CONTROLLER","outputs":[{"internalType":"contract IOpenseaConduitController","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"IMPL","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SEAPORT","outputs":[{"internalType":"contract IOpenseaExchange","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"VAULT_FACTORY","outputs":[{"internalType":"contract IFractionalV1VaultFactory","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ZORA","outputs":[{"internalType":"contract IZoraAuctionHouse","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"proposalId","type":"uint256"}],"name":"cancelProposal","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"proposalId","type":"uint256"},{"internalType":"bytes","name":"proposalData","type":"bytes"},{"internalType":"bytes","name":"progressData","type":"bytes"},{"internalType":"bytes","name":"extraData","type":"bytes"},{"internalType":"uint256","name":"flags","type":"uint256"},{"internalType":"contract IERC721[]","name":"preciousTokens","type":"address[]"},{"internalType":"uint256[]","name":"preciousTokenIds","type":"uint256[]"}],"internalType":"struct IProposalExecutionEngine.ExecuteProposalParams","name":"params","type":"tuple"}],"name":"executeProposal","outputs":[{"internalType":"bytes","name":"nextProgressData","type":"bytes"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getCurrentInProgressProposalId","outputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"oldImpl","type":"address"},{"internalType":"bytes","name":"initializeData","type":"bytes"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
6101a06040523480156200001257600080fd5b50604051620046e0380380620046e0833981016040819052620000359162000091565b306080526001600160a01b0393841660a05291831660c05292821660e0819052928216610100819052610120849052911661014052610160526101805262000111565b6001600160a01b03811681146200008e57600080fd5b50565b600080600080600060a08688031215620000aa57600080fd5b8551620000b78162000078565b6020870151909550620000ca8162000078565b6040870151909450620000dd8162000078565b6060870151909350620000f08162000078565b6080870151909250620001038162000078565b809150509295509295909350565b60805160a05160c05160e05161010051610120516101405161016051610180516144c56200021b60003960006112ee01526000612ebb015260008181609d01528181610be401528181610c650152610df70152600081816107fc0152818161089301526109910152600081816101a6015281816119a901528181611a6501528181611ba00152611cb40152600081816114b00152818161154701528181611723015281816117ba015281816121ef015261248701526000818161015f01526122730152600081816101110152818161287c015281816129f40152612fb2015260008181610138015281816101fc015281816103db0152818161042901526113b801526144c56000f3fe608060405234801561001057600080fd5b50600436106100935760003560e01c80639b0f5c41116100665780639b0f5c411461015a578063a7c8a3f914610181578063c4e525bf146101a1578063d1f57894146101c8578063e0a8f6f5146101dd57600080fd5b8063103f2907146100985780631d117029146100dc578063387b66291461010c57806356973ee514610133575b600080fd5b6100bf7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020015b60405180910390f35b7f33a3c164d6872de9f70b5a8072fe8ec5d3a6af6642df9b59e4bb0c4c5ce80e23546040519081526020016100d3565b6100bf7f000000000000000000000000000000000000000000000000000000000000000081565b6100bf7f000000000000000000000000000000000000000000000000000000000000000081565b6100bf7f000000000000000000000000000000000000000000000000000000000000000081565b61019461018f366004613400565b6101f0565b6040516100d39190613560565b6100bf7f000000000000000000000000000000000000000000000000000000000000000081565b6101db6101d6366004613573565b6103d1565b005b6101db6101eb3660046135f7565b61041f565b60606001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016300361023b5760405163ea2cbbd560e01b815260040160405180910390fd5b815160000361025d5760405163eaeba8a760e01b815260040160405180910390fd5b7f33a3c164d6872de9f70b5a8072fe8ec5d3a6af6642df9b59e4bb0c4c5ce80e23547f33a3c164d6872de9f70b5a8072fe8ec5d3a6af6642df9b59e4bb0c4c5ce80e229060008190036102b657835160018301556102e9565b835181146102e957835160405163432e608d60e11b81526004810191909152602481018290526044015b60405180910390fd5b8154600081900361034357811561030257610302613610565b6040850151511561033e578460400151805190602001208160405163070bdb0360e11b81526004016102e0929190918252602082015260400190565b61037c565b6040850151805160209091012081811461037a5760405163070bdb0360e11b815260048101829052602481018390526044016102e0565b505b5060001982556020840151600090610393906104ff565b602087015290506103a48186610581565b935083516000036103bf5760006001840181905583556103c9565b8351602085012083555b505050919050565b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016300361041a5760405163ea2cbbd560e01b815260040160405180910390fd5b505050565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001630036104685760405163ea2cbbd560e01b815260040160405180910390fd5b806000036104895760405163eaeba8a760e01b815260040160405180910390fd5b7f33a3c164d6872de9f70b5a8072fe8ec5d3a6af6642df9b59e4bb0c4c5ce80e23547f33a3c164d6872de9f70b5a8072fe8ec5d3a6af6642df9b59e4bb0c4c5ce80e22908281146104f057604051633ae4fbbd60e11b8152600481018490526024016102e0565b50600060018201819055905550565b6000606060048351101561052657604051632fc4a01d60e21b815260040160405180910390fd5b5050600481018051825160031901825263ffffffff1690600082600681111561055157610551613626565b0361055b57600080fd5b6006828181111561056e5761056e613626565b60ff16111561057c57600080fd5b915091565b6060600183600681111561059757610597613626565b036105ac576105a582610699565b9050610693565b60068360068111156105c0576105c0613626565b036105ce576105a582610753565b60028360068111156105e2576105e2613626565b036105f0576105a58261077b565b600383600681111561060457610604613626565b03610612576105a582610b40565b600483600681111561062657610626613626565b03610634576105a582611019565b600583600681111561064857610648613626565b0361065f5761065a82602001516112b1565b610693565b82600681111561067157610671613626565b60405163efdc945f60e01b815263ffffffff90911660048201526024016102e0565b92915050565b6060600082602001518060200190518101906106b59190613738565b905061074c836040518061012001604052808460000151815260200184600001518152602001846020015164ffffffffff168152602001600060018111156106ff576106ff613626565b815260200184604001516001600160a01b0316815260200184606001518152602001846080015181526020018460a0015181526020018460c001516001600160e01b031916815250611413565b9392505050565b60606000826020015180602001905181019061076f9190613827565b905061074c8382611413565b606060008260200151806020019051810190610797919061391f565b905060008360400151516000146107c55783604001518060200190518101906107c091906139a2565b6107c8565b60005b905060008160018111156107de576107de613626565b03610acd57604051631106aeeb60e21b8152601060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063441abbac90602401602060405180830381865afa15801561084b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061086f91906139bf565b604051631106aeeb60e21b8152601160048201529091506000906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063441abbac90602401602060405180830381865afa1580156108da573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108fe91906139bf565b905064ffffffffff82161580159061092757508164ffffffffff16846040015164ffffffffff16105b1561093e5764ffffffffff82166040850152610978565b64ffffffffff81161580159061096557508064ffffffffff16846040015164ffffffffff16115b156109785764ffffffffff811660408501525b604051631106aeeb60e21b8152601260048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063441abbac90602401602060405180830381865afa1580156109e0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a0491906139bf565b905064ffffffffff811615801590610a2d57508064ffffffffff16856020015164ffffffffff16115b15610a405764ffffffffff811660208601525b5050506000610a6683600001518460200151856040015186606001518760800151611992565b905060016040518060400160405280838152602001610a9a866020015164ffffffffff1642610a9591906139ee565b611b58565b64ffffffffff169052604051610ab4929190602001613a11565b6040516020818303038152906040529350505050919050565b6001816001811115610ae157610ae1613626565b14610aee57610aee613610565b60008460400151806020019051810190610b089190613a95565b915050610b278160000151826020015185606001518660800151611b87565b5050604080516020810190915260008152949350505050565b606060008260200151806020019051810190610b5c9190613acb565b90506000306001600160a01b031663b20240ee6040518163ffffffff1660e01b8152600401608060405180830381865afa158015610b9e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bc29190613b22565b606001518251602084015160405163095ea7b360e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116600483015260248201929092526bffffffffffffffffffffffff9093169350169063095ea7b390604401600060405180830381600087803b158015610c4957600080fd5b505af1158015610c5d573d6000803e3d6000fd5b5050505060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663bdc01110306001600160a01b03166306fdde036040518163ffffffff1660e01b8152600401600060405180830381865afa158015610cd0573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610cf89190810190613bea565b306001600160a01b03166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa158015610d36573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610d5e9190810190613bea565b865160208801516040516001600160e01b031960e087901b168152610d90949392919089906000908190600401613c32565b6020604051808303816000875af1158015610daf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610dd391906139bf565b604051634632752560e11b8152600481018290529091506000906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690638c64ea4a90602401602060405180830381865afa158015610e3e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e629190613c8b565b6040516370a0823160e01b815230600482015290915083906001600160a01b038316906370a0823190602401602060405180830381865afa158015610eab573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ecf91906139bf565b14610edc57610edc613610565b604051630c6a62dd60e01b8152600160048201526001600160a01b03821690630c6a62dd90602401600060405180830381600087803b158015610f1e57600080fd5b505af1158015610f32573d6000803e3d6000fd5b50505050836020015184600001516001600160a01b03167fd252747f4bdd4d75edc8c1d9cf1446e23083a5ea163955dfb64fe82a66fc3c998484604051610f8c9291909182526001600160a01b0316602082015260400190565b60405180910390a3604051637d1eeb0f60e11b8152309063fa3dd61e90610fbc9060019085908790600401613ca8565b60e0604051808303816000875af1158015610fdb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fff9190613cf2565b505060408051602081019091526000815295945050505050565b6060600082602001518060200190518101906110359190613dc2565b9050600060018085608001511614905060008460c00151516001600160401b03811115611064576110646131cb565b60405190808252806020026020018201604052801561108d578160200160208202803683370190505b509050816111195760005b8151811015611117576110e58660a0015182815181106110ba576110ba613ed2565b60200260200101518760c0015183815181106110d8576110d8613ed2565b6020026020010151611e36565b8282815181106110f7576110f7613ed2565b9115156020928302919091019091015261111081613ee8565b9050611098565b505b3460005b84518110156111ba5761113c81868960a001518a60c001518887611e5d565b84818151811061114e5761114e613ed2565b602002602001015160200151826111659190613f01565b8751865160408051928352602083018590528201529092507fb7ff498e3c62b4b7e752fe0641134387db1cc5096d26b462a2c949bfb8484a9a9060600160405180910390a16111b381613ee8565b905061111d565b50826112a15760005b825181101561129f578281815181106111de576111de613ed2565b60200260200101511561128f576112228760a00151828151811061120457611204613ed2565b60200260200101518860c0015183815181106110d8576110d8613ed2565b61128f578660a00151818151811061123c5761123c613ed2565b60200260200101518760c00151828151811061125a5761125a613ed2565b6020908102919091010151604051634baa335b60e11b81526001600160a01b03909216600483015260248201526044016102e0565b61129881613ee8565b90506111c3565b505b8015610b2757610b273382611fcd565b600080828060200190518101906112c89190613f14565b604051635c9fcd8560e11b81526002600482015291935091506000906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063b93f9b0a90602401602060405180830381865afa158015611335573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113599190613c8b565b9050806001600160a01b0316836001600160a01b0316146113a057604051630987f3d960e11b81526001600160a01b038083166004830152841660248201526044016102e0565b6113aa8183612059565b604080516001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081168252851660208201527f171f44298b88c4e0b1c126daf5a75eabcd04d9dd623209ed50e7c98622e067d6910160405180910390a150505050565b60606000600180856080015116149050600084604001515160001461144f57846040015180602001905181019061144a9190613f64565b611452565b60005b9050600081600381111561146857611468613626565b036116435781158015611492575061149284608001518560a001518760a001518860c00151612142565b1561163f57604051631106aeeb60e21b8152600660048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063441abbac90602401602060405180830381865afa1580156114ff573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061152391906139bf565b604051631106aeeb60e21b8152600760048201529091506000906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063441abbac90602401602060405180830381865afa15801561158e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115b291906139bf565b905064ffffffffff82161561163c5760006115dc876000015184848a608001518b60a00151611992565b9050600160405180604001604052808381526020016116078664ffffffffff1642610a9591906139ee565b64ffffffffff169052604051611621929190602001613f95565b60405160208183030381529060405295505050505050610693565b50505b5060025b600181600381111561165757611657613626565b036116f157600085604001518060200190518101906116769190613fb3565b91505060006116978260000151836020015188608001518960a00151611b87565b905060008160028111156116ad576116ad613626565b14806116ca575060028160028111156116c8576116c8613626565b145b156116ea5760405180602001604052806000815250945050505050610693565b6002925050505b600281600381111561170557611705613626565b0361191d57604051631106aeeb60e21b8152601360048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063441abbac90602401602060405180830381865afa158015611772573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061179691906139bf565b604051631106aeeb60e21b8152601460048201529091506000906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063441abbac90602401602060405180830381865afa158015611801573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061182591906139bf565b905064ffffffffff82161580159061184e57508164ffffffffff16866040015164ffffffffff16105b156118655764ffffffffff8216604087015261189f565b64ffffffffff81161580159061188c57508064ffffffffff16866040015164ffffffffff16115b1561189f5764ffffffffff811660408701525b50506000846040015164ffffffffff16426118ba91906139ee565b90506000806118d687608001518860a0015189606001516121cc565b9150915060006118e78883866123d3565b905060038184866040516020016119019493929190613fcf565b6040516020818303038152906040529650505050505050610693565b600381600381111561193157611931613626565b1461193e5761193e613610565b600085604001518060200190518101906119589190614001565b915050610b2781600001518260200151836040015164ffffffffff1688608001518960a001518a606001518b600001518c602001516129db565b60405163095ea7b360e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166004830152602482018390526000919084169063095ea7b390604401600060405180830381600087803b158015611a0057600080fd5b505af1158015611a14573d6000803e3d6000fd5b50506040516375e9249f60e01b8152600481018590526001600160a01b03868116602483015264ffffffffff88166044830152606482018a905260006084830181905260a4830181905260c48301527f00000000000000000000000000000000000000000000000000000000000000001692506375e9249f915060e4016020604051808303816000875af1158015611ab0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ad491906139bf565b90507f92160616bc72fa0e7854d06cb31ed32d6900a787a287808c4677802fb57a22548184848988611b0d64ffffffffff8c16426139ee565b604080519687526001600160a01b03909516602087015293850192909252606084015264ffffffffff90811660808401521660a082015260c00160405180910390a195945050505050565b600064ffffffffff821115611b8357604051633ce0460960e21b8152600481018390526024016102e0565b5090565b604051635cd16f1d60e11b8152600481018590526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063b9a2de3a90602401600060405180830381600087803b158015611bec57600080fd5b505af1925050508015611bfd575060015b611d9a573d808015611c2b576040519150601f19603f3d011682016040523d82523d6000602084013e611c30565b606091505b50805160208201207fab5ac877486bd286449032bffed3a1798df77c605e9f81e0dbaaa711cab16a9b8101611d63574264ffffffffff168664ffffffffff161115611c9e57604051633d9251e560e11b81526004810188905264ffffffffff871660248201526044016102e0565b6040516396b5a75560e01b8152600481018890527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906396b5a75590602401600060405180830381600087803b158015611d0057600080fd5b505af1158015611d14573d6000803e3d6000fd5b5050604080518a815264ffffffffff8a1660208201527f2b5e0f760dfa65f0b373807db413cde4fb501792f679c6c9fb2f810f6fa1f4ad935001905060405180910390a1600192505050611e2e565b7f474ba0184a7cd5de777156a56f3859150719340a6974b6ee50f05c58139f4dc28114611d9357611d9382612cb2565b5050611df7565b30611dae6001600160a01b03851684612cba565b6001600160a01b031603611df7576040518581527f95df91b4115069deb8a25fad93b97ea21cdda12fa1842726adb91f847bbd0f099060200160405180910390a1506002611e2e565b6040518581527f5f773413a86a1bb5ab358fb19f7d47a4cc78ab91102af8103505f05362214c819060200160405180910390a15060005b949350505050565b600030611e4c6001600160a01b03851684612cba565b6001600160a01b0316149392505050565b6000858781518110611e7157611e71613ed2565b60200260200101519050611e8a81848989518989612da3565b611eb057805160408083015190516309a30f6560e01b81526102e092919060040161408e565b8060200151821015611ee557602081015160405163465352eb60e01b81526004810191909152602481018390526044016102e0565b60008082600001516001600160a01b031683602001518460400151604051611f0d91906140b2565b60006040518083038185875af1925050503d8060008114611f4a576040519150601f19603f3d011682016040523d82523d6000602084013e611f4f565b606091505b509150915081611f7457806040516308a16a4360e41b81526004016102e09190613560565b606083015115611fc2578051602082012060608401518114611fc05760608401516040516395fcd9af60e01b8152600481018c90526024810183905260448101919091526064016102e0565b505b505050505050505050565b80600003611fd9575050565b600080836001600160a01b03168360405160006040518083038185875af1925050503d8060008114612027576040519150601f19603f3d011682016040523d82523d6000602084013e61202c565b606091505b50915091508161205357838160405163354db69760e01b81526004016102e092919061408e565b50505050565b7feb054550c406db3b89dc7016369a66aff0ce40188133281942b92e6188c6b1ef80546001600160a01b031981166001600160a01b03858116918217845560405192169160009182916120b2908590889060240161408e565b60408051601f198184030181529181526020820180516001600160e01b031663347d5e2560e21b179052516120e791906140b2565b600060405180830381855af49150503d8060008114612122576040519150601f19603f3d011682016040523d82523d6000602084013e612127565b606091505b50915091508161213a5761213a81612cb2565b505050505050565b6000805b83518110156121c05783818151811061216157612161613ed2565b60200260200101516001600160a01b0316866001600160a01b03161480156121a1575082818151811061219657612196613ed2565b602002602001015185145b156121b0576001915050611e2e565b6121b981613ee8565b9050612146565b50600095945050505050565b6040516324dfc9d760e01b8152600d600482015260009081906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906324dfc9d790602401602060405180830381865afa158015612236573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061225a91906139bf565b604051636e9bfd9f60e01b8152600481018290529091507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690636e9bfd9f906024016040805180830381865afa1580156122c1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122e591906140de565b50915060008360018111156122fc576122fc613626565b036123685760405163095ea7b360e01b81526001600160a01b0383811660048301526024820186905286169063095ea7b390604401600060405180830381600087803b15801561234b57600080fd5b505af115801561235f573d6000803e3d6000fd5b505050506123cb565b60405163a22cb46560e01b81526001600160a01b0383811660048301526001602483015286169063a22cb46590604401600060405180830381600087803b1580156123b257600080fd5b505af11580156123c6573d6000803e3d6000fd5b505050505b935093915050565b60008360e00151518460c0015151146123ff57604051631b1cf91760e21b815260040160405180910390fd5b604080516001808252818301909252600091816020015b61241e61312e565b81526020019060019003908161241657905050905060008160008151811061244857612448613ed2565b602090810291909101015180513081524260a082015260c08101869052604051635c9fcd8560e11b8152600e6004820152919250906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063b93f9b0a90602401602060405180830381865afa1580156124ce573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124f29190613c8b565b6001600160a01b0316602082018190521561250e576002612511565b60005b8160800190600381111561252757612527613626565b9081600381111561253a5761253a613626565b905250610100808801516001600160e01b03191690820152610120810186905260c08701515161256b9060016139ee565b61014082015260408051600180825281830190925290816020015b6125c26040805160a08101909152806000815260200160006001600160a01b031681526020016000815260200160008152602001600081525090565b8152602001906001900390816125865750506040820181905280516000919082906125ef576125ef613ed2565b602002602001015190506000600181111561260c5761260c613626565b8860600151600181111561262257612622613626565b1461262e576003612631565b60025b8190600581111561264457612644613626565b9081600581111561265757612657613626565b9052506080808901516001600160a01b0316602083015260a0890151604083015260016060830181905290820181905260c089015151612696916139ee565b6001600160401b038111156126ad576126ad6131cb565b60405190808252806020026020018201604052801561270d57816020015b6040805160c08101825260008082526020808301829052928201819052606082018190526080820181905260a082015282526000199092019101816126cb5790505b5060608301819052805160009190829061272957612729613ed2565b6020908102919091018101516000808252818301819052604082018190528b516060830152918b015160808201523060a082015291505b8960c001515181101561285857606084015161277d8260016139ee565b8151811061278d5761278d613ed2565b6020908102919091010151915060008281905250600060208301819052604083015260c08a01518051829081106127c6576127c6613ed2565b602002602001015182606001818152505089600001518a602001518b60c0015183815181106127f7576127f7613ed2565b6020026020010151612809919061410a565b6128139190614121565b608083015260e08a015180518290811061282f5761282f613ed2565b60209081029190910101516001600160a01b031660a083015261285181613ee8565b9050612760565b5061286283612f83565b60405163440a3b9960e11b81529096506001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906388147732906128b1908890600401614307565b6020604051808303816000875af11580156128d0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128f4919061438c565b61290057612900613610565b60008960600151600181111561291857612918613626565b148015612929575060208901518951145b1561297b57608089015160a08a01518a516040517f8bc0df75fcb1089ed0bc3c5aaeee9eb67fd03058afcce4f505c3876a170f6d639361296e9388938c938e906143a7565b60405180910390a16129cf565b7fa7a458fb56579e1739b7d7be315c8376100992f6cc2a7bed18e57de1ec54781083878b608001518c60a001518d600001518e602001518d6040516129c697969594939291906143ec565b60405180910390a15b50505050509392505050565b6040516346423aa760e01b8152600481018990526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906346423aa790602401608060405180830381865afa158015612a43573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a679190614439565b509250505080600014612b43576000846001811115612a8857612a88613626565b148015612a9457508183145b15612aef57604080518a81526001600160a01b0388166020820152908101869052606081018490527f3e99b32c69260aa9463ba7c7f903dceed3e9cdc2709c00c858c887fa9bc5b9e5906080015b60405180910390a1611fc2565b604080518a81526001600160a01b038816602082015290810186905260608101849052608081018390527f496e331a08ff376957a7e057d214af9c47e131093374097b5fb5c005819b331c9060a001612ae2565b428711612c79576000846001811115612b5e57612b5e613626565b03612bc95760405163095ea7b360e01b815260006004820152602481018690526001600160a01b0387169063095ea7b390604401600060405180830381600087803b158015612bac57600080fd5b505af1158015612bc0573d6000803e3d6000fd5b50505050612c2c565b60405163a22cb46560e01b81526001600160a01b0389811660048301526000602483015287169063a22cb46590604401600060405180830381600087803b158015612c1357600080fd5b505af1158015612c27573d6000803e3d6000fd5b505050505b604080518a81526001600160a01b0388166020820152908101869052606081018890527f2045cfa9b677ebd0cb44d8ba225aaa166881e63d27a156115c76cafb3f0b395d90608001612ae2565b60405163079be7e360e41b8152600481018a90526001600160a01b038716602482015260448101869052606481018890526084016102e0565b805160208201fd5b6000806000846001600160a01b0316856001600160a01b0316636352211e86604051602401612ceb91815260200190565b60408051601f198184030181529181526020820180516001600160e01b031660e09490941b939093179092529051612d2392506140b2565b600060405180830381855afa9150503d8060008114612d5e576040519150601f19603f3d011682016040523d82523d6000602084013e612d63565b606091505b5091509150811580612d76575060208151105b15612d8657600092505050610693565b80806020019051810190612d9a9190613c8b565b95945050505050565b6000306001600160a01b031687600001516001600160a01b031603612dca57506000612f79565b600487604001515110612f75576040870151602001516001600160e01b03191686612ef85763f6a1584d60e01b6001600160e01b0319821601612e4b57600080612e178a60400151613039565b90925090506001600160a01b03821615612e44578951612e3990828888612142565b159350505050612f79565b5050612ef8565b635dd34b9b60e01b6001600160e01b0319821601612e97576000612e728960400151613080565b9150508015612e91578851612e8790866130cb565b1592505050612f79565b50612ef8565b63694a58ab60e01b6001600160e01b0319821601612ef85787516001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116911603612ef85784612eef8760016139ee565b14915050612f79565b6001600160e01b03198116630a85bd0160e11b1480612f2757506001600160e01b0319811663f23a6e6160e01b145b80612f4257506001600160e01b0319811663bc197c8160e01b145b15612f51576000915050612f79565b633bf5c46760e11b6001600160e01b0319821601612f73576000915050612f79565b505b5060015b9695505050505050565b61014081018051600091829052612f9861314e565b506040516379df72bd60e01b815283906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906379df72bd90612fe790849060040161447c565b602060405180830381865afa158015613004573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061302891906139bf565b610140909401919091525090919050565b60008060448351101561306457825160405163252e3c3d60e01b81526004016102e091815260200190565b6001600160a01b03602484015116915060448301519050915091565b6000806044835110156130ab57825160405163252e3c3d60e01b81526004016102e091815260200190565b6001600160a01b0360248401511691506001604484015115189050915091565b6000805b8251811015613124578281815181106130ea576130ea613ed2565b60200260200101516001600160a01b0316846001600160a01b031603613114576001915050610693565b61311d81613ee8565b90506130cf565b5060009392505050565b604051806040016040528061314161314e565b8152602001606081525090565b60405180610160016040528060006001600160a01b0316815260200160006001600160a01b0316815260200160608152602001606081526020016000600381111561319b5761319b613626565b815260006020820181905260408201819052606082018190526080820181905260a0820181905260c09091015290565b634e487b7160e01b600052604160045260246000fd5b60405160e081016001600160401b0381118282101715613203576132036131cb565b60405290565b60405161012081016001600160401b0381118282101715613203576132036131cb565b604051608081016001600160401b0381118282101715613203576132036131cb565b604051601f8201601f191681016001600160401b0381118282101715613276576132766131cb565b604052919050565b60006001600160401b03821115613297576132976131cb565b50601f01601f191660200190565b600082601f8301126132b657600080fd5b81356132c96132c48261327e565b61324e565b8181528460208386010111156132de57600080fd5b816020850160208301376000918101602001919091529392505050565b60006001600160401b03821115613314576133146131cb565b5060051b60200190565b6001600160a01b038116811461333357600080fd5b50565b600082601f83011261334757600080fd5b813560206133576132c4836132fb565b82815260059290921b8401810191818101908684111561337657600080fd5b8286015b8481101561339a57803561338d8161331e565b835291830191830161337a565b509695505050505050565b600082601f8301126133b657600080fd5b813560206133c66132c4836132fb565b82815260059290921b840181019181810190868411156133e557600080fd5b8286015b8481101561339a57803583529183019183016133e9565b60006020828403121561341257600080fd5b81356001600160401b038082111561342957600080fd5b9083019060e0828603121561343d57600080fd5b6134456131e1565b8235815260208301358281111561345b57600080fd5b613467878286016132a5565b60208301525060408301358281111561347f57600080fd5b61348b878286016132a5565b6040830152506060830135828111156134a357600080fd5b6134af878286016132a5565b6060830152506080830135608082015260a0830135828111156134d157600080fd5b6134dd87828601613336565b60a08301525060c0830135828111156134f557600080fd5b613501878286016133a5565b60c08301525095945050505050565b60005b8381101561352b578181015183820152602001613513565b50506000910152565b6000815180845261354c816020860160208601613510565b601f01601f19169290920160200192915050565b60208152600061074c6020830184613534565b60008060006040848603121561358857600080fd5b83356135938161331e565b925060208401356001600160401b03808211156135af57600080fd5b818601915086601f8301126135c357600080fd5b8135818111156135d257600080fd5b8760208285010111156135e457600080fd5b6020830194508093505050509250925092565b60006020828403121561360957600080fd5b5035919050565b634e487b7160e01b600052600160045260246000fd5b634e487b7160e01b600052602160045260246000fd5b805164ffffffffff8116811461365157600080fd5b919050565b80516136518161331e565b600082601f83011261367257600080fd5b815160206136826132c4836132fb565b82815260059290921b840181019181810190868411156136a157600080fd5b8286015b8481101561339a57805183529183019183016136a5565b600082601f8301126136cd57600080fd5b815160206136dd6132c4836132fb565b82815260059290921b840181019181810190868411156136fc57600080fd5b8286015b8481101561339a5780516137138161331e565b8352918301918301613700565b80516001600160e01b03198116811461365157600080fd5b60006020828403121561374a57600080fd5b81516001600160401b038082111561376157600080fd5b9083019060e0828603121561377557600080fd5b61377d6131e1565b8251815261378d6020840161363c565b602082015261379e60408401613656565b6040820152606083015160608201526080830151828111156137bf57600080fd5b6137cb87828601613661565b60808301525060a0830151828111156137e357600080fd5b6137ef878286016136bc565b60a08301525061380160c08401613720565b60c082015295945050505050565b6002811061333357600080fd5b80516136518161380f565b60006020828403121561383957600080fd5b81516001600160401b038082111561385057600080fd5b90830190610120828603121561386557600080fd5b61386d613209565b82518152602083015160208201526138876040840161363c565b60408201526138986060840161381c565b60608201526138a960808401613656565b608082015260a083015160a082015260c0830151828111156138ca57600080fd5b6138d687828601613661565b60c08301525060e0830151828111156138ee57600080fd5b6138fa878286016136bc565b60e0830152506101009150613910828401613720565b91810191909152949350505050565b600060a0828403121561393157600080fd5b60405160a081018181106001600160401b0382111715613953576139536131cb565b604052825181526139666020840161363c565b60208201526139776040840161363c565b6040820152606083015161398a8161331e565b60608201526080928301519281019290925250919050565b6000602082840312156139b457600080fd5b815161074c8161380f565b6000602082840312156139d157600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b80820180821115610693576106936139d8565b6002811061333357613333613626565b60608101613a1e84613a01565b83825261074c60208301848051825260209081015164ffffffffff16910152565b600060408284031215613a5157600080fd5b604051604081018181106001600160401b0382111715613a7357613a736131cb565b60405282518152905080613a896020840161363c565b60208201525092915050565b60008060608385031215613aa857600080fd5b8251613ab38161380f565b9150613ac28460208501613a3f565b90509250929050565b600060408284031215613add57600080fd5b604051604081018181106001600160401b0382111715613aff57613aff6131cb565b6040528251613b0d8161331e565b81526020928301519281019290925250919050565b600060808284031215613b3457600080fd5b604051608081018181106001600160401b0382111715613b5657613b566131cb565b604052613b628361363c565b8152613b706020840161363c565b6020820152604083015161ffff81168114613b8a57600080fd5b604082015260608301516bffffffffffffffffffffffff81168114613bae57600080fd5b60608201529392505050565b6000613bc86132c48461327e565b9050828152838383011115613bdc57600080fd5b61074c836020830184613510565b600060208284031215613bfc57600080fd5b81516001600160401b03811115613c1257600080fd5b8201601f81018413613c2357600080fd5b611e2e84825160208401613bba565b60e081526000613c4560e083018a613534565b8281036020840152613c57818a613534565b6001600160a01b0398909816604084015250506060810194909452608084019290925260a083015260c09091015292915050565b600060208284031215613c9d57600080fd5b815161074c8161331e565b60608101613cb585613a01565b9381526001600160a01b0392909216602083015260409091015290565b80516fffffffffffffffffffffffffffffffff8116811461365157600080fd5b600060e08284031215613d0457600080fd5b60405160e081018181106001600160401b0382111715613d2657613d266131cb565b6040528251613d348161380f565b8152602083810151908201526040830151613d4e8161331e565b60408201526060830151613d618161331e565b60608201526080830151613d748161331e565b6080820152613d8560a08401613cd2565b60a0820152613d9660c08401613cd2565b60c08201529392505050565b600082601f830112613db357600080fd5b61074c83835160208501613bba565b60006020808385031215613dd557600080fd5b82516001600160401b0380821115613dec57600080fd5b818501915085601f830112613e0057600080fd5b8151613e0e6132c4826132fb565b81815260059190911b83018401908481019088831115613e2d57600080fd5b8585015b83811015613ec557805185811115613e4857600080fd5b86016080818c03601f19011215613e5f5760008081fd5b613e6761322c565b88820151613e748161331e565b81526040828101518a83015260608084015189811115613e945760008081fd5b613ea28f8d83880101613da2565b928401929092526080939093015192820192909252845250918601918601613e31565b5098975050505050505050565b634e487b7160e01b600052603260045260246000fd5b600060018201613efa57613efa6139d8565b5060010190565b81810381811115610693576106936139d8565b60008060408385031215613f2757600080fd5b8251613f328161331e565b60208401519092506001600160401b03811115613f4e57600080fd5b613f5a85828601613da2565b9150509250929050565b600060208284031215613f7657600080fd5b81516004811061074c57600080fd5b6004811061333357613333613626565b60608101613a1e84613f85565b805160ff8116811461365157600080fd5b60008060608385031215613fc657600080fd5b613ab383613fa2565b60808101613fdc86613f85565b94815260208101939093526001600160a01b0391909116604083015260609091015290565b600080828403608081121561401557600080fd5b61401e84613fa2565b92506060601f198201121561403257600080fd5b50604051606081018181106001600160401b0382111715614055576140556131cb565b60409081526020850151825284015161406d8161331e565b602082015261407e6060850161363c565b6040820152809150509250929050565b6001600160a01b0383168152604060208201819052600090611e2e90830184613534565b600082516140c4818460208701613510565b9190910192915050565b8051801515811461365157600080fd5b600080604083850312156140f157600080fd5b82516140fc8161331e565b9150613ac2602084016140ce565b8082028115828204841417610693576106936139d8565b60008261413e57634e487b7160e01b600052601260045260246000fd5b500490565b6006811061415357614153613626565b9052565b600081518084526020808501945080840160005b838110156141c1578151614180888251614143565b838101516001600160a01b03168885015260408082015190890152606080820151908901526080908101519088015260a0909601959082019060010161416b565b509495945050505050565b600081518084526020808501945080840160005b838110156141c15781516141f5888251614143565b808401516001600160a01b0390811689860152604080830151908a0152606080830151908a0152608080830151908a015260a091820151169088015260c090960195908201906001016141e0565b61415381613f85565b80516001600160a01b031682526000610160602083015161427860208601826001600160a01b03169052565b50604083015181604086015261429082860182614157565b915050606083015184820360608601526142aa82826141cc565b91505060808301516142bf6080860182614243565b5060a0838101519085015260c0808401519085015260e08084015190850152610100808401519085015261012080840151908501526101409283015192909301919091525090565b60006020808301818452808551808352604092508286019150828160051b87010184880160005b8381101561437e57888303603f19018552815180518785526143528886018261424c565b91890151858303868b015291905061436a8183613534565b96890196945050509086019060010161432e565b509098975050505050505050565b60006020828403121561439e57600080fd5b61074c826140ce565b60c0815260006143ba60c083018961424c565b6020830197909752506001600160a01b039490941660408501526060840192909252608083015260a090910152919050565b60e0815260006143ff60e083018a61424c565b6020830198909852506001600160a01b039590951660408601526060850193909352608084019190915260a083015260c090910152919050565b6000806000806080858703121561444f57600080fd5b614458856140ce565b9350614466602086016140ce565b6040860151606090960151949790965092505050565b60208152600061074c602083018461424c56fea2646970667358221220b8dd4cd5ba3f14e7fa395b99a1d5709ab631e49e032eae33fc17d59bfa3d4e1464736f6c634300081100330000000000000000000000001ca20040ce6ad406bc2a6c89976388829e7fbade00000000000000000000000000000000000001ad428e4906ae43d8f9852d0dd600000000000000000000000000000000f9490004c11cef243f5400493c00ad63000000000000000000000000e468ce99444174bd3bbbed09209577d25d1ad67300000000000000000000000085aa7f78bdb2de8f3e0c0010d99ad5853ffcfc63
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106100935760003560e01c80639b0f5c41116100665780639b0f5c411461015a578063a7c8a3f914610181578063c4e525bf146101a1578063d1f57894146101c8578063e0a8f6f5146101dd57600080fd5b8063103f2907146100985780631d117029146100dc578063387b66291461010c57806356973ee514610133575b600080fd5b6100bf7f00000000000000000000000085aa7f78bdb2de8f3e0c0010d99ad5853ffcfc6381565b6040516001600160a01b0390911681526020015b60405180910390f35b7f33a3c164d6872de9f70b5a8072fe8ec5d3a6af6642df9b59e4bb0c4c5ce80e23546040519081526020016100d3565b6100bf7f00000000000000000000000000000000000001ad428e4906ae43d8f9852d0dd681565b6100bf7f000000000000000000000000731db043762729ea2dae790a1c4a6ad78b86d67c81565b6100bf7f00000000000000000000000000000000f9490004c11cef243f5400493c00ad6381565b61019461018f366004613400565b6101f0565b6040516100d39190613560565b6100bf7f000000000000000000000000e468ce99444174bd3bbbed09209577d25d1ad67381565b6101db6101d6366004613573565b6103d1565b005b6101db6101eb3660046135f7565b61041f565b60606001600160a01b037f000000000000000000000000731db043762729ea2dae790a1c4a6ad78b86d67c16300361023b5760405163ea2cbbd560e01b815260040160405180910390fd5b815160000361025d5760405163eaeba8a760e01b815260040160405180910390fd5b7f33a3c164d6872de9f70b5a8072fe8ec5d3a6af6642df9b59e4bb0c4c5ce80e23547f33a3c164d6872de9f70b5a8072fe8ec5d3a6af6642df9b59e4bb0c4c5ce80e229060008190036102b657835160018301556102e9565b835181146102e957835160405163432e608d60e11b81526004810191909152602481018290526044015b60405180910390fd5b8154600081900361034357811561030257610302613610565b6040850151511561033e578460400151805190602001208160405163070bdb0360e11b81526004016102e0929190918252602082015260400190565b61037c565b6040850151805160209091012081811461037a5760405163070bdb0360e11b815260048101829052602481018390526044016102e0565b505b5060001982556020840151600090610393906104ff565b602087015290506103a48186610581565b935083516000036103bf5760006001840181905583556103c9565b8351602085012083555b505050919050565b6001600160a01b037f000000000000000000000000731db043762729ea2dae790a1c4a6ad78b86d67c16300361041a5760405163ea2cbbd560e01b815260040160405180910390fd5b505050565b6001600160a01b037f000000000000000000000000731db043762729ea2dae790a1c4a6ad78b86d67c1630036104685760405163ea2cbbd560e01b815260040160405180910390fd5b806000036104895760405163eaeba8a760e01b815260040160405180910390fd5b7f33a3c164d6872de9f70b5a8072fe8ec5d3a6af6642df9b59e4bb0c4c5ce80e23547f33a3c164d6872de9f70b5a8072fe8ec5d3a6af6642df9b59e4bb0c4c5ce80e22908281146104f057604051633ae4fbbd60e11b8152600481018490526024016102e0565b50600060018201819055905550565b6000606060048351101561052657604051632fc4a01d60e21b815260040160405180910390fd5b5050600481018051825160031901825263ffffffff1690600082600681111561055157610551613626565b0361055b57600080fd5b6006828181111561056e5761056e613626565b60ff16111561057c57600080fd5b915091565b6060600183600681111561059757610597613626565b036105ac576105a582610699565b9050610693565b60068360068111156105c0576105c0613626565b036105ce576105a582610753565b60028360068111156105e2576105e2613626565b036105f0576105a58261077b565b600383600681111561060457610604613626565b03610612576105a582610b40565b600483600681111561062657610626613626565b03610634576105a582611019565b600583600681111561064857610648613626565b0361065f5761065a82602001516112b1565b610693565b82600681111561067157610671613626565b60405163efdc945f60e01b815263ffffffff90911660048201526024016102e0565b92915050565b6060600082602001518060200190518101906106b59190613738565b905061074c836040518061012001604052808460000151815260200184600001518152602001846020015164ffffffffff168152602001600060018111156106ff576106ff613626565b815260200184604001516001600160a01b0316815260200184606001518152602001846080015181526020018460a0015181526020018460c001516001600160e01b031916815250611413565b9392505050565b60606000826020015180602001905181019061076f9190613827565b905061074c8382611413565b606060008260200151806020019051810190610797919061391f565b905060008360400151516000146107c55783604001518060200190518101906107c091906139a2565b6107c8565b60005b905060008160018111156107de576107de613626565b03610acd57604051631106aeeb60e21b8152601060048201526000907f0000000000000000000000001ca20040ce6ad406bc2a6c89976388829e7fbade6001600160a01b03169063441abbac90602401602060405180830381865afa15801561084b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061086f91906139bf565b604051631106aeeb60e21b8152601160048201529091506000906001600160a01b037f0000000000000000000000001ca20040ce6ad406bc2a6c89976388829e7fbade169063441abbac90602401602060405180830381865afa1580156108da573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108fe91906139bf565b905064ffffffffff82161580159061092757508164ffffffffff16846040015164ffffffffff16105b1561093e5764ffffffffff82166040850152610978565b64ffffffffff81161580159061096557508064ffffffffff16846040015164ffffffffff16115b156109785764ffffffffff811660408501525b604051631106aeeb60e21b8152601260048201526000907f0000000000000000000000001ca20040ce6ad406bc2a6c89976388829e7fbade6001600160a01b03169063441abbac90602401602060405180830381865afa1580156109e0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a0491906139bf565b905064ffffffffff811615801590610a2d57508064ffffffffff16856020015164ffffffffff16115b15610a405764ffffffffff811660208601525b5050506000610a6683600001518460200151856040015186606001518760800151611992565b905060016040518060400160405280838152602001610a9a866020015164ffffffffff1642610a9591906139ee565b611b58565b64ffffffffff169052604051610ab4929190602001613a11565b6040516020818303038152906040529350505050919050565b6001816001811115610ae157610ae1613626565b14610aee57610aee613610565b60008460400151806020019051810190610b089190613a95565b915050610b278160000151826020015185606001518660800151611b87565b5050604080516020810190915260008152949350505050565b606060008260200151806020019051810190610b5c9190613acb565b90506000306001600160a01b031663b20240ee6040518163ffffffff1660e01b8152600401608060405180830381865afa158015610b9e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bc29190613b22565b606001518251602084015160405163095ea7b360e01b81526001600160a01b037f00000000000000000000000085aa7f78bdb2de8f3e0c0010d99ad5853ffcfc638116600483015260248201929092526bffffffffffffffffffffffff9093169350169063095ea7b390604401600060405180830381600087803b158015610c4957600080fd5b505af1158015610c5d573d6000803e3d6000fd5b5050505060007f00000000000000000000000085aa7f78bdb2de8f3e0c0010d99ad5853ffcfc636001600160a01b031663bdc01110306001600160a01b03166306fdde036040518163ffffffff1660e01b8152600401600060405180830381865afa158015610cd0573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610cf89190810190613bea565b306001600160a01b03166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa158015610d36573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610d5e9190810190613bea565b865160208801516040516001600160e01b031960e087901b168152610d90949392919089906000908190600401613c32565b6020604051808303816000875af1158015610daf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610dd391906139bf565b604051634632752560e11b8152600481018290529091506000906001600160a01b037f00000000000000000000000085aa7f78bdb2de8f3e0c0010d99ad5853ffcfc631690638c64ea4a90602401602060405180830381865afa158015610e3e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e629190613c8b565b6040516370a0823160e01b815230600482015290915083906001600160a01b038316906370a0823190602401602060405180830381865afa158015610eab573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ecf91906139bf565b14610edc57610edc613610565b604051630c6a62dd60e01b8152600160048201526001600160a01b03821690630c6a62dd90602401600060405180830381600087803b158015610f1e57600080fd5b505af1158015610f32573d6000803e3d6000fd5b50505050836020015184600001516001600160a01b03167fd252747f4bdd4d75edc8c1d9cf1446e23083a5ea163955dfb64fe82a66fc3c998484604051610f8c9291909182526001600160a01b0316602082015260400190565b60405180910390a3604051637d1eeb0f60e11b8152309063fa3dd61e90610fbc9060019085908790600401613ca8565b60e0604051808303816000875af1158015610fdb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fff9190613cf2565b505060408051602081019091526000815295945050505050565b6060600082602001518060200190518101906110359190613dc2565b9050600060018085608001511614905060008460c00151516001600160401b03811115611064576110646131cb565b60405190808252806020026020018201604052801561108d578160200160208202803683370190505b509050816111195760005b8151811015611117576110e58660a0015182815181106110ba576110ba613ed2565b60200260200101518760c0015183815181106110d8576110d8613ed2565b6020026020010151611e36565b8282815181106110f7576110f7613ed2565b9115156020928302919091019091015261111081613ee8565b9050611098565b505b3460005b84518110156111ba5761113c81868960a001518a60c001518887611e5d565b84818151811061114e5761114e613ed2565b602002602001015160200151826111659190613f01565b8751865160408051928352602083018590528201529092507fb7ff498e3c62b4b7e752fe0641134387db1cc5096d26b462a2c949bfb8484a9a9060600160405180910390a16111b381613ee8565b905061111d565b50826112a15760005b825181101561129f578281815181106111de576111de613ed2565b60200260200101511561128f576112228760a00151828151811061120457611204613ed2565b60200260200101518860c0015183815181106110d8576110d8613ed2565b61128f578660a00151818151811061123c5761123c613ed2565b60200260200101518760c00151828151811061125a5761125a613ed2565b6020908102919091010151604051634baa335b60e11b81526001600160a01b03909216600483015260248201526044016102e0565b61129881613ee8565b90506111c3565b505b8015610b2757610b273382611fcd565b600080828060200190518101906112c89190613f14565b604051635c9fcd8560e11b81526002600482015291935091506000906001600160a01b037f0000000000000000000000001ca20040ce6ad406bc2a6c89976388829e7fbade169063b93f9b0a90602401602060405180830381865afa158015611335573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113599190613c8b565b9050806001600160a01b0316836001600160a01b0316146113a057604051630987f3d960e11b81526001600160a01b038083166004830152841660248201526044016102e0565b6113aa8183612059565b604080516001600160a01b037f000000000000000000000000731db043762729ea2dae790a1c4a6ad78b86d67c81168252851660208201527f171f44298b88c4e0b1c126daf5a75eabcd04d9dd623209ed50e7c98622e067d6910160405180910390a150505050565b60606000600180856080015116149050600084604001515160001461144f57846040015180602001905181019061144a9190613f64565b611452565b60005b9050600081600381111561146857611468613626565b036116435781158015611492575061149284608001518560a001518760a001518860c00151612142565b1561163f57604051631106aeeb60e21b8152600660048201526000907f0000000000000000000000001ca20040ce6ad406bc2a6c89976388829e7fbade6001600160a01b03169063441abbac90602401602060405180830381865afa1580156114ff573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061152391906139bf565b604051631106aeeb60e21b8152600760048201529091506000906001600160a01b037f0000000000000000000000001ca20040ce6ad406bc2a6c89976388829e7fbade169063441abbac90602401602060405180830381865afa15801561158e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115b291906139bf565b905064ffffffffff82161561163c5760006115dc876000015184848a608001518b60a00151611992565b9050600160405180604001604052808381526020016116078664ffffffffff1642610a9591906139ee565b64ffffffffff169052604051611621929190602001613f95565b60405160208183030381529060405295505050505050610693565b50505b5060025b600181600381111561165757611657613626565b036116f157600085604001518060200190518101906116769190613fb3565b91505060006116978260000151836020015188608001518960a00151611b87565b905060008160028111156116ad576116ad613626565b14806116ca575060028160028111156116c8576116c8613626565b145b156116ea5760405180602001604052806000815250945050505050610693565b6002925050505b600281600381111561170557611705613626565b0361191d57604051631106aeeb60e21b8152601360048201526000907f0000000000000000000000001ca20040ce6ad406bc2a6c89976388829e7fbade6001600160a01b03169063441abbac90602401602060405180830381865afa158015611772573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061179691906139bf565b604051631106aeeb60e21b8152601460048201529091506000906001600160a01b037f0000000000000000000000001ca20040ce6ad406bc2a6c89976388829e7fbade169063441abbac90602401602060405180830381865afa158015611801573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061182591906139bf565b905064ffffffffff82161580159061184e57508164ffffffffff16866040015164ffffffffff16105b156118655764ffffffffff8216604087015261189f565b64ffffffffff81161580159061188c57508064ffffffffff16866040015164ffffffffff16115b1561189f5764ffffffffff811660408701525b50506000846040015164ffffffffff16426118ba91906139ee565b90506000806118d687608001518860a0015189606001516121cc565b9150915060006118e78883866123d3565b905060038184866040516020016119019493929190613fcf565b6040516020818303038152906040529650505050505050610693565b600381600381111561193157611931613626565b1461193e5761193e613610565b600085604001518060200190518101906119589190614001565b915050610b2781600001518260200151836040015164ffffffffff1688608001518960a001518a606001518b600001518c602001516129db565b60405163095ea7b360e01b81526001600160a01b037f000000000000000000000000e468ce99444174bd3bbbed09209577d25d1ad67381166004830152602482018390526000919084169063095ea7b390604401600060405180830381600087803b158015611a0057600080fd5b505af1158015611a14573d6000803e3d6000fd5b50506040516375e9249f60e01b8152600481018590526001600160a01b03868116602483015264ffffffffff88166044830152606482018a905260006084830181905260a4830181905260c48301527f000000000000000000000000e468ce99444174bd3bbbed09209577d25d1ad6731692506375e9249f915060e4016020604051808303816000875af1158015611ab0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ad491906139bf565b90507f92160616bc72fa0e7854d06cb31ed32d6900a787a287808c4677802fb57a22548184848988611b0d64ffffffffff8c16426139ee565b604080519687526001600160a01b03909516602087015293850192909252606084015264ffffffffff90811660808401521660a082015260c00160405180910390a195945050505050565b600064ffffffffff821115611b8357604051633ce0460960e21b8152600481018390526024016102e0565b5090565b604051635cd16f1d60e11b8152600481018590526000907f000000000000000000000000e468ce99444174bd3bbbed09209577d25d1ad6736001600160a01b03169063b9a2de3a90602401600060405180830381600087803b158015611bec57600080fd5b505af1925050508015611bfd575060015b611d9a573d808015611c2b576040519150601f19603f3d011682016040523d82523d6000602084013e611c30565b606091505b50805160208201207fab5ac877486bd286449032bffed3a1798df77c605e9f81e0dbaaa711cab16a9b8101611d63574264ffffffffff168664ffffffffff161115611c9e57604051633d9251e560e11b81526004810188905264ffffffffff871660248201526044016102e0565b6040516396b5a75560e01b8152600481018890527f000000000000000000000000e468ce99444174bd3bbbed09209577d25d1ad6736001600160a01b0316906396b5a75590602401600060405180830381600087803b158015611d0057600080fd5b505af1158015611d14573d6000803e3d6000fd5b5050604080518a815264ffffffffff8a1660208201527f2b5e0f760dfa65f0b373807db413cde4fb501792f679c6c9fb2f810f6fa1f4ad935001905060405180910390a1600192505050611e2e565b7f474ba0184a7cd5de777156a56f3859150719340a6974b6ee50f05c58139f4dc28114611d9357611d9382612cb2565b5050611df7565b30611dae6001600160a01b03851684612cba565b6001600160a01b031603611df7576040518581527f95df91b4115069deb8a25fad93b97ea21cdda12fa1842726adb91f847bbd0f099060200160405180910390a1506002611e2e565b6040518581527f5f773413a86a1bb5ab358fb19f7d47a4cc78ab91102af8103505f05362214c819060200160405180910390a15060005b949350505050565b600030611e4c6001600160a01b03851684612cba565b6001600160a01b0316149392505050565b6000858781518110611e7157611e71613ed2565b60200260200101519050611e8a81848989518989612da3565b611eb057805160408083015190516309a30f6560e01b81526102e092919060040161408e565b8060200151821015611ee557602081015160405163465352eb60e01b81526004810191909152602481018390526044016102e0565b60008082600001516001600160a01b031683602001518460400151604051611f0d91906140b2565b60006040518083038185875af1925050503d8060008114611f4a576040519150601f19603f3d011682016040523d82523d6000602084013e611f4f565b606091505b509150915081611f7457806040516308a16a4360e41b81526004016102e09190613560565b606083015115611fc2578051602082012060608401518114611fc05760608401516040516395fcd9af60e01b8152600481018c90526024810183905260448101919091526064016102e0565b505b505050505050505050565b80600003611fd9575050565b600080836001600160a01b03168360405160006040518083038185875af1925050503d8060008114612027576040519150601f19603f3d011682016040523d82523d6000602084013e61202c565b606091505b50915091508161205357838160405163354db69760e01b81526004016102e092919061408e565b50505050565b7feb054550c406db3b89dc7016369a66aff0ce40188133281942b92e6188c6b1ef80546001600160a01b031981166001600160a01b03858116918217845560405192169160009182916120b2908590889060240161408e565b60408051601f198184030181529181526020820180516001600160e01b031663347d5e2560e21b179052516120e791906140b2565b600060405180830381855af49150503d8060008114612122576040519150601f19603f3d011682016040523d82523d6000602084013e612127565b606091505b50915091508161213a5761213a81612cb2565b505050505050565b6000805b83518110156121c05783818151811061216157612161613ed2565b60200260200101516001600160a01b0316866001600160a01b03161480156121a1575082818151811061219657612196613ed2565b602002602001015185145b156121b0576001915050611e2e565b6121b981613ee8565b9050612146565b50600095945050505050565b6040516324dfc9d760e01b8152600d600482015260009081906001600160a01b037f0000000000000000000000001ca20040ce6ad406bc2a6c89976388829e7fbade16906324dfc9d790602401602060405180830381865afa158015612236573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061225a91906139bf565b604051636e9bfd9f60e01b8152600481018290529091507f00000000000000000000000000000000f9490004c11cef243f5400493c00ad636001600160a01b031690636e9bfd9f906024016040805180830381865afa1580156122c1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122e591906140de565b50915060008360018111156122fc576122fc613626565b036123685760405163095ea7b360e01b81526001600160a01b0383811660048301526024820186905286169063095ea7b390604401600060405180830381600087803b15801561234b57600080fd5b505af115801561235f573d6000803e3d6000fd5b505050506123cb565b60405163a22cb46560e01b81526001600160a01b0383811660048301526001602483015286169063a22cb46590604401600060405180830381600087803b1580156123b257600080fd5b505af11580156123c6573d6000803e3d6000fd5b505050505b935093915050565b60008360e00151518460c0015151146123ff57604051631b1cf91760e21b815260040160405180910390fd5b604080516001808252818301909252600091816020015b61241e61312e565b81526020019060019003908161241657905050905060008160008151811061244857612448613ed2565b602090810291909101015180513081524260a082015260c08101869052604051635c9fcd8560e11b8152600e6004820152919250906001600160a01b037f0000000000000000000000001ca20040ce6ad406bc2a6c89976388829e7fbade169063b93f9b0a90602401602060405180830381865afa1580156124ce573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124f29190613c8b565b6001600160a01b0316602082018190521561250e576002612511565b60005b8160800190600381111561252757612527613626565b9081600381111561253a5761253a613626565b905250610100808801516001600160e01b03191690820152610120810186905260c08701515161256b9060016139ee565b61014082015260408051600180825281830190925290816020015b6125c26040805160a08101909152806000815260200160006001600160a01b031681526020016000815260200160008152602001600081525090565b8152602001906001900390816125865750506040820181905280516000919082906125ef576125ef613ed2565b602002602001015190506000600181111561260c5761260c613626565b8860600151600181111561262257612622613626565b1461262e576003612631565b60025b8190600581111561264457612644613626565b9081600581111561265757612657613626565b9052506080808901516001600160a01b0316602083015260a0890151604083015260016060830181905290820181905260c089015151612696916139ee565b6001600160401b038111156126ad576126ad6131cb565b60405190808252806020026020018201604052801561270d57816020015b6040805160c08101825260008082526020808301829052928201819052606082018190526080820181905260a082015282526000199092019101816126cb5790505b5060608301819052805160009190829061272957612729613ed2565b6020908102919091018101516000808252818301819052604082018190528b516060830152918b015160808201523060a082015291505b8960c001515181101561285857606084015161277d8260016139ee565b8151811061278d5761278d613ed2565b6020908102919091010151915060008281905250600060208301819052604083015260c08a01518051829081106127c6576127c6613ed2565b602002602001015182606001818152505089600001518a602001518b60c0015183815181106127f7576127f7613ed2565b6020026020010151612809919061410a565b6128139190614121565b608083015260e08a015180518290811061282f5761282f613ed2565b60209081029190910101516001600160a01b031660a083015261285181613ee8565b9050612760565b5061286283612f83565b60405163440a3b9960e11b81529096506001600160a01b037f00000000000000000000000000000000000001ad428e4906ae43d8f9852d0dd616906388147732906128b1908890600401614307565b6020604051808303816000875af11580156128d0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128f4919061438c565b61290057612900613610565b60008960600151600181111561291857612918613626565b148015612929575060208901518951145b1561297b57608089015160a08a01518a516040517f8bc0df75fcb1089ed0bc3c5aaeee9eb67fd03058afcce4f505c3876a170f6d639361296e9388938c938e906143a7565b60405180910390a16129cf565b7fa7a458fb56579e1739b7d7be315c8376100992f6cc2a7bed18e57de1ec54781083878b608001518c60a001518d600001518e602001518d6040516129c697969594939291906143ec565b60405180910390a15b50505050509392505050565b6040516346423aa760e01b8152600481018990526000907f00000000000000000000000000000000000001ad428e4906ae43d8f9852d0dd66001600160a01b0316906346423aa790602401608060405180830381865afa158015612a43573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a679190614439565b509250505080600014612b43576000846001811115612a8857612a88613626565b148015612a9457508183145b15612aef57604080518a81526001600160a01b0388166020820152908101869052606081018490527f3e99b32c69260aa9463ba7c7f903dceed3e9cdc2709c00c858c887fa9bc5b9e5906080015b60405180910390a1611fc2565b604080518a81526001600160a01b038816602082015290810186905260608101849052608081018390527f496e331a08ff376957a7e057d214af9c47e131093374097b5fb5c005819b331c9060a001612ae2565b428711612c79576000846001811115612b5e57612b5e613626565b03612bc95760405163095ea7b360e01b815260006004820152602481018690526001600160a01b0387169063095ea7b390604401600060405180830381600087803b158015612bac57600080fd5b505af1158015612bc0573d6000803e3d6000fd5b50505050612c2c565b60405163a22cb46560e01b81526001600160a01b0389811660048301526000602483015287169063a22cb46590604401600060405180830381600087803b158015612c1357600080fd5b505af1158015612c27573d6000803e3d6000fd5b505050505b604080518a81526001600160a01b0388166020820152908101869052606081018890527f2045cfa9b677ebd0cb44d8ba225aaa166881e63d27a156115c76cafb3f0b395d90608001612ae2565b60405163079be7e360e41b8152600481018a90526001600160a01b038716602482015260448101869052606481018890526084016102e0565b805160208201fd5b6000806000846001600160a01b0316856001600160a01b0316636352211e86604051602401612ceb91815260200190565b60408051601f198184030181529181526020820180516001600160e01b031660e09490941b939093179092529051612d2392506140b2565b600060405180830381855afa9150503d8060008114612d5e576040519150601f19603f3d011682016040523d82523d6000602084013e612d63565b606091505b5091509150811580612d76575060208151105b15612d8657600092505050610693565b80806020019051810190612d9a9190613c8b565b95945050505050565b6000306001600160a01b031687600001516001600160a01b031603612dca57506000612f79565b600487604001515110612f75576040870151602001516001600160e01b03191686612ef85763f6a1584d60e01b6001600160e01b0319821601612e4b57600080612e178a60400151613039565b90925090506001600160a01b03821615612e44578951612e3990828888612142565b159350505050612f79565b5050612ef8565b635dd34b9b60e01b6001600160e01b0319821601612e97576000612e728960400151613080565b9150508015612e91578851612e8790866130cb565b1592505050612f79565b50612ef8565b63694a58ab60e01b6001600160e01b0319821601612ef85787516001600160a01b037f000000000000000000000000e468ce99444174bd3bbbed09209577d25d1ad6738116911603612ef85784612eef8760016139ee565b14915050612f79565b6001600160e01b03198116630a85bd0160e11b1480612f2757506001600160e01b0319811663f23a6e6160e01b145b80612f4257506001600160e01b0319811663bc197c8160e01b145b15612f51576000915050612f79565b633bf5c46760e11b6001600160e01b0319821601612f73576000915050612f79565b505b5060015b9695505050505050565b61014081018051600091829052612f9861314e565b506040516379df72bd60e01b815283906001600160a01b037f00000000000000000000000000000000000001ad428e4906ae43d8f9852d0dd616906379df72bd90612fe790849060040161447c565b602060405180830381865afa158015613004573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061302891906139bf565b610140909401919091525090919050565b60008060448351101561306457825160405163252e3c3d60e01b81526004016102e091815260200190565b6001600160a01b03602484015116915060448301519050915091565b6000806044835110156130ab57825160405163252e3c3d60e01b81526004016102e091815260200190565b6001600160a01b0360248401511691506001604484015115189050915091565b6000805b8251811015613124578281815181106130ea576130ea613ed2565b60200260200101516001600160a01b0316846001600160a01b031603613114576001915050610693565b61311d81613ee8565b90506130cf565b5060009392505050565b604051806040016040528061314161314e565b8152602001606081525090565b60405180610160016040528060006001600160a01b0316815260200160006001600160a01b0316815260200160608152602001606081526020016000600381111561319b5761319b613626565b815260006020820181905260408201819052606082018190526080820181905260a0820181905260c09091015290565b634e487b7160e01b600052604160045260246000fd5b60405160e081016001600160401b0381118282101715613203576132036131cb565b60405290565b60405161012081016001600160401b0381118282101715613203576132036131cb565b604051608081016001600160401b0381118282101715613203576132036131cb565b604051601f8201601f191681016001600160401b0381118282101715613276576132766131cb565b604052919050565b60006001600160401b03821115613297576132976131cb565b50601f01601f191660200190565b600082601f8301126132b657600080fd5b81356132c96132c48261327e565b61324e565b8181528460208386010111156132de57600080fd5b816020850160208301376000918101602001919091529392505050565b60006001600160401b03821115613314576133146131cb565b5060051b60200190565b6001600160a01b038116811461333357600080fd5b50565b600082601f83011261334757600080fd5b813560206133576132c4836132fb565b82815260059290921b8401810191818101908684111561337657600080fd5b8286015b8481101561339a57803561338d8161331e565b835291830191830161337a565b509695505050505050565b600082601f8301126133b657600080fd5b813560206133c66132c4836132fb565b82815260059290921b840181019181810190868411156133e557600080fd5b8286015b8481101561339a57803583529183019183016133e9565b60006020828403121561341257600080fd5b81356001600160401b038082111561342957600080fd5b9083019060e0828603121561343d57600080fd5b6134456131e1565b8235815260208301358281111561345b57600080fd5b613467878286016132a5565b60208301525060408301358281111561347f57600080fd5b61348b878286016132a5565b6040830152506060830135828111156134a357600080fd5b6134af878286016132a5565b6060830152506080830135608082015260a0830135828111156134d157600080fd5b6134dd87828601613336565b60a08301525060c0830135828111156134f557600080fd5b613501878286016133a5565b60c08301525095945050505050565b60005b8381101561352b578181015183820152602001613513565b50506000910152565b6000815180845261354c816020860160208601613510565b601f01601f19169290920160200192915050565b60208152600061074c6020830184613534565b60008060006040848603121561358857600080fd5b83356135938161331e565b925060208401356001600160401b03808211156135af57600080fd5b818601915086601f8301126135c357600080fd5b8135818111156135d257600080fd5b8760208285010111156135e457600080fd5b6020830194508093505050509250925092565b60006020828403121561360957600080fd5b5035919050565b634e487b7160e01b600052600160045260246000fd5b634e487b7160e01b600052602160045260246000fd5b805164ffffffffff8116811461365157600080fd5b919050565b80516136518161331e565b600082601f83011261367257600080fd5b815160206136826132c4836132fb565b82815260059290921b840181019181810190868411156136a157600080fd5b8286015b8481101561339a57805183529183019183016136a5565b600082601f8301126136cd57600080fd5b815160206136dd6132c4836132fb565b82815260059290921b840181019181810190868411156136fc57600080fd5b8286015b8481101561339a5780516137138161331e565b8352918301918301613700565b80516001600160e01b03198116811461365157600080fd5b60006020828403121561374a57600080fd5b81516001600160401b038082111561376157600080fd5b9083019060e0828603121561377557600080fd5b61377d6131e1565b8251815261378d6020840161363c565b602082015261379e60408401613656565b6040820152606083015160608201526080830151828111156137bf57600080fd5b6137cb87828601613661565b60808301525060a0830151828111156137e357600080fd5b6137ef878286016136bc565b60a08301525061380160c08401613720565b60c082015295945050505050565b6002811061333357600080fd5b80516136518161380f565b60006020828403121561383957600080fd5b81516001600160401b038082111561385057600080fd5b90830190610120828603121561386557600080fd5b61386d613209565b82518152602083015160208201526138876040840161363c565b60408201526138986060840161381c565b60608201526138a960808401613656565b608082015260a083015160a082015260c0830151828111156138ca57600080fd5b6138d687828601613661565b60c08301525060e0830151828111156138ee57600080fd5b6138fa878286016136bc565b60e0830152506101009150613910828401613720565b91810191909152949350505050565b600060a0828403121561393157600080fd5b60405160a081018181106001600160401b0382111715613953576139536131cb565b604052825181526139666020840161363c565b60208201526139776040840161363c565b6040820152606083015161398a8161331e565b60608201526080928301519281019290925250919050565b6000602082840312156139b457600080fd5b815161074c8161380f565b6000602082840312156139d157600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b80820180821115610693576106936139d8565b6002811061333357613333613626565b60608101613a1e84613a01565b83825261074c60208301848051825260209081015164ffffffffff16910152565b600060408284031215613a5157600080fd5b604051604081018181106001600160401b0382111715613a7357613a736131cb565b60405282518152905080613a896020840161363c565b60208201525092915050565b60008060608385031215613aa857600080fd5b8251613ab38161380f565b9150613ac28460208501613a3f565b90509250929050565b600060408284031215613add57600080fd5b604051604081018181106001600160401b0382111715613aff57613aff6131cb565b6040528251613b0d8161331e565b81526020928301519281019290925250919050565b600060808284031215613b3457600080fd5b604051608081018181106001600160401b0382111715613b5657613b566131cb565b604052613b628361363c565b8152613b706020840161363c565b6020820152604083015161ffff81168114613b8a57600080fd5b604082015260608301516bffffffffffffffffffffffff81168114613bae57600080fd5b60608201529392505050565b6000613bc86132c48461327e565b9050828152838383011115613bdc57600080fd5b61074c836020830184613510565b600060208284031215613bfc57600080fd5b81516001600160401b03811115613c1257600080fd5b8201601f81018413613c2357600080fd5b611e2e84825160208401613bba565b60e081526000613c4560e083018a613534565b8281036020840152613c57818a613534565b6001600160a01b0398909816604084015250506060810194909452608084019290925260a083015260c09091015292915050565b600060208284031215613c9d57600080fd5b815161074c8161331e565b60608101613cb585613a01565b9381526001600160a01b0392909216602083015260409091015290565b80516fffffffffffffffffffffffffffffffff8116811461365157600080fd5b600060e08284031215613d0457600080fd5b60405160e081018181106001600160401b0382111715613d2657613d266131cb565b6040528251613d348161380f565b8152602083810151908201526040830151613d4e8161331e565b60408201526060830151613d618161331e565b60608201526080830151613d748161331e565b6080820152613d8560a08401613cd2565b60a0820152613d9660c08401613cd2565b60c08201529392505050565b600082601f830112613db357600080fd5b61074c83835160208501613bba565b60006020808385031215613dd557600080fd5b82516001600160401b0380821115613dec57600080fd5b818501915085601f830112613e0057600080fd5b8151613e0e6132c4826132fb565b81815260059190911b83018401908481019088831115613e2d57600080fd5b8585015b83811015613ec557805185811115613e4857600080fd5b86016080818c03601f19011215613e5f5760008081fd5b613e6761322c565b88820151613e748161331e565b81526040828101518a83015260608084015189811115613e945760008081fd5b613ea28f8d83880101613da2565b928401929092526080939093015192820192909252845250918601918601613e31565b5098975050505050505050565b634e487b7160e01b600052603260045260246000fd5b600060018201613efa57613efa6139d8565b5060010190565b81810381811115610693576106936139d8565b60008060408385031215613f2757600080fd5b8251613f328161331e565b60208401519092506001600160401b03811115613f4e57600080fd5b613f5a85828601613da2565b9150509250929050565b600060208284031215613f7657600080fd5b81516004811061074c57600080fd5b6004811061333357613333613626565b60608101613a1e84613f85565b805160ff8116811461365157600080fd5b60008060608385031215613fc657600080fd5b613ab383613fa2565b60808101613fdc86613f85565b94815260208101939093526001600160a01b0391909116604083015260609091015290565b600080828403608081121561401557600080fd5b61401e84613fa2565b92506060601f198201121561403257600080fd5b50604051606081018181106001600160401b0382111715614055576140556131cb565b60409081526020850151825284015161406d8161331e565b602082015261407e6060850161363c565b6040820152809150509250929050565b6001600160a01b0383168152604060208201819052600090611e2e90830184613534565b600082516140c4818460208701613510565b9190910192915050565b8051801515811461365157600080fd5b600080604083850312156140f157600080fd5b82516140fc8161331e565b9150613ac2602084016140ce565b8082028115828204841417610693576106936139d8565b60008261413e57634e487b7160e01b600052601260045260246000fd5b500490565b6006811061415357614153613626565b9052565b600081518084526020808501945080840160005b838110156141c1578151614180888251614143565b838101516001600160a01b03168885015260408082015190890152606080820151908901526080908101519088015260a0909601959082019060010161416b565b509495945050505050565b600081518084526020808501945080840160005b838110156141c15781516141f5888251614143565b808401516001600160a01b0390811689860152604080830151908a0152606080830151908a0152608080830151908a015260a091820151169088015260c090960195908201906001016141e0565b61415381613f85565b80516001600160a01b031682526000610160602083015161427860208601826001600160a01b03169052565b50604083015181604086015261429082860182614157565b915050606083015184820360608601526142aa82826141cc565b91505060808301516142bf6080860182614243565b5060a0838101519085015260c0808401519085015260e08084015190850152610100808401519085015261012080840151908501526101409283015192909301919091525090565b60006020808301818452808551808352604092508286019150828160051b87010184880160005b8381101561437e57888303603f19018552815180518785526143528886018261424c565b91890151858303868b015291905061436a8183613534565b96890196945050509086019060010161432e565b509098975050505050505050565b60006020828403121561439e57600080fd5b61074c826140ce565b60c0815260006143ba60c083018961424c565b6020830197909752506001600160a01b039490941660408501526060840192909252608083015260a090910152919050565b60e0815260006143ff60e083018a61424c565b6020830198909852506001600160a01b039590951660408601526060850193909352608084019190915260a083015260c090910152919050565b6000806000806080858703121561444f57600080fd5b614458856140ce565b9350614466602086016140ce565b6040860151606090960151949790965092505050565b60208152600061074c602083018461424c56fea2646970667358221220b8dd4cd5ba3f14e7fa395b99a1d5709ab631e49e032eae33fc17d59bfa3d4e1464736f6c63430008110033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000001ca20040ce6ad406bc2a6c89976388829e7fbade00000000000000000000000000000000000001ad428e4906ae43d8f9852d0dd600000000000000000000000000000000f9490004c11cef243f5400493c00ad63000000000000000000000000e468ce99444174bd3bbbed09209577d25d1ad67300000000000000000000000085aa7f78bdb2de8f3e0c0010d99ad5853ffcfc63
-----Decoded View---------------
Arg [0] : globals (address): 0x1cA20040cE6aD406bC2A6c89976388829E7fbAde
Arg [1] : seaport (address): 0x00000000000001ad428e4906aE43D8F9852d0dD6
Arg [2] : seaportConduitController (address): 0x00000000F9490004C11Cef243f5400493c00Ad63
Arg [3] : zoraAuctionHouse (address): 0xE468cE99444174Bd3bBBEd09209577d25D1ad673
Arg [4] : fractionalVaultFactory (address): 0x85Aa7f78BdB2DE8F3e0c0010d99AD5853fFcfC63
-----Encoded View---------------
5 Constructor Arguments found :
Arg [0] : 0000000000000000000000001ca20040ce6ad406bc2a6c89976388829e7fbade
Arg [1] : 00000000000000000000000000000000000001ad428e4906ae43d8f9852d0dd6
Arg [2] : 00000000000000000000000000000000f9490004c11cef243f5400493c00ad63
Arg [3] : 000000000000000000000000e468ce99444174bd3bbbed09209577d25d1ad673
Arg [4] : 00000000000000000000000085aa7f78bdb2de8f3e0c0010d99ad5853ffcfc63
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
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.