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:
Token
Compiler Version
v0.8.16+commit.07a7930e
Optimization Enabled:
Yes with 500000 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity 0.8.16; import { UUPS } from "../lib/proxy/UUPS.sol"; import { ReentrancyGuard } from "../lib/utils/ReentrancyGuard.sol"; import { ERC721Votes } from "../lib/token/ERC721Votes.sol"; import { ERC721 } from "../lib/token/ERC721.sol"; import { Ownable } from "../lib/utils/Ownable.sol"; import { TokenStorageV1 } from "./storage/TokenStorageV1.sol"; import { IBaseMetadata } from "./metadata/interfaces/IBaseMetadata.sol"; import { IManager } from "../manager/IManager.sol"; import { IAuction } from "../auction/IAuction.sol"; import { IToken } from "./IToken.sol"; import { VersionedContract } from "../VersionedContract.sol"; /// @title Token /// @author Rohan Kulkarni /// @custom:repo github.com/ourzora/nouns-protocol /// @notice A DAO's ERC-721 governance token contract Token is IToken, VersionedContract, UUPS, Ownable, ReentrancyGuard, ERC721Votes, TokenStorageV1 { /// /// /// IMMUTABLES /// /// /// /// @notice The contract upgrade manager IManager private immutable manager; /// /// /// CONSTRUCTOR /// /// /// /// @param _manager The contract upgrade manager address constructor(address _manager) payable initializer { manager = IManager(_manager); } /// /// /// INITIALIZER /// /// /// /// @notice Initializes a DAO's ERC-721 token contract /// @param _founders The DAO founders /// @param _initStrings The encoded token and metadata initialization strings /// @param _metadataRenderer The token's metadata renderer /// @param _auction The token's auction house /// @param _initialOwner The initial owner of the token function initialize( IManager.FounderParams[] calldata _founders, bytes calldata _initStrings, address _metadataRenderer, address _auction, address _initialOwner ) external initializer { // Ensure the caller is the contract manager if (msg.sender != address(manager)) { revert ONLY_MANAGER(); } // Initialize the reentrancy guard __ReentrancyGuard_init(); // Setup ownable __Ownable_init(_initialOwner); // Store the founders and compute their allocations _addFounders(_founders); // Decode the token name and symbol (string memory _name, string memory _symbol, , , , ) = abi.decode(_initStrings, (string, string, string, string, string, string)); // Initialize the ERC-721 token __ERC721_init(_name, _symbol); // Store the metadata renderer and auction house settings.metadataRenderer = IBaseMetadata(_metadataRenderer); settings.auction = _auction; } /// @notice Called by the auction upon the first unpause / token mint to transfer ownership from founder to treasury /// @dev Only callable by the auction contract function onFirstAuctionStarted() external override { if (msg.sender != settings.auction) { revert ONLY_AUCTION(); } // Force transfer ownership to the treasury _transferOwnership(IAuction(settings.auction).treasury()); } /// @notice Called upon initialization to add founders and compute their vesting allocations /// @dev We do this by reserving an mapping of [0-100] token indices, such that if a new token mint ID % 100 is reserved, it's sent to the appropriate founder. /// @param _founders The list of DAO founders function _addFounders(IManager.FounderParams[] calldata _founders) internal { // Used to store the total percent ownership among the founders uint256 totalOwnership; uint8 numFoundersAdded = 0; unchecked { // For each founder: for (uint256 i; i < _founders.length; ++i) { // Cache the percent ownership uint256 founderPct = _founders[i].ownershipPct; // Continue if no ownership is specified if (founderPct == 0) { continue; } // Update the total ownership and ensure it's valid totalOwnership += founderPct; // Check that founders own less than 100% of tokens if (totalOwnership > 99) { revert INVALID_FOUNDER_OWNERSHIP(); } // Compute the founder's id uint256 founderId = numFoundersAdded++; // Get the pointer to store the founder Founder storage newFounder = founder[founderId]; // Store the founder's vesting details newFounder.wallet = _founders[i].wallet; newFounder.vestExpiry = uint32(_founders[i].vestExpiry); // Total ownership cannot be above 100 so this fits safely in uint8 newFounder.ownershipPct = uint8(founderPct); // Compute the vesting schedule uint256 schedule = 100 / founderPct; // Used to store the base token id the founder will recieve uint256 baseTokenId; // For each token to vest: for (uint256 j; j < founderPct; ++j) { // Get the available token id baseTokenId = _getNextTokenId(baseTokenId); // Store the founder as the recipient tokenRecipient[baseTokenId] = newFounder; emit MintScheduled(baseTokenId, founderId, newFounder); // Update the base token id baseTokenId = (baseTokenId + schedule) % 100; } } // Store the founders' details settings.totalOwnership = uint8(totalOwnership); settings.numFounders = numFoundersAdded; } } /// @dev Finds the next available base token id for a founder /// @param _tokenId The ERC-721 token id function _getNextTokenId(uint256 _tokenId) internal view returns (uint256) { unchecked { while (tokenRecipient[_tokenId].wallet != address(0)) { _tokenId = (++_tokenId) % 100; } return _tokenId; } } /// /// /// MINT /// /// /// /// @notice Mints tokens to the auction house for bidding and handles founder vesting function mint() external nonReentrant returns (uint256 tokenId) { // Cache the auction address address minter = settings.auction; // Ensure the caller is the auction if (msg.sender != minter) { revert ONLY_AUCTION(); } // Cannot realistically overflow unchecked { do { // Get the next token to mint tokenId = settings.mintCount++; // Lookup whether the token is for a founder, and mint accordingly if so } while (_isForFounder(tokenId)); } // Mint the next available token to the auction house for bidding _mint(minter, tokenId); } /// @dev Overrides _mint to include attribute generation /// @param _to The token recipient /// @param _tokenId The ERC-721 token id function _mint(address _to, uint256 _tokenId) internal override { // Mint the token super._mint(_to, _tokenId); // Increment the total supply unchecked { ++settings.totalSupply; } // Generate the token attributes if (!settings.metadataRenderer.onMinted(_tokenId)) revert NO_METADATA_GENERATED(); } /// @dev Checks if a given token is for a founder and mints accordingly /// @param _tokenId The ERC-721 token id function _isForFounder(uint256 _tokenId) private returns (bool) { // Get the base token id uint256 baseTokenId = _tokenId % 100; // If there is no scheduled recipient: if (tokenRecipient[baseTokenId].wallet == address(0)) { return false; // Else if the founder is still vesting: } else if (block.timestamp < tokenRecipient[baseTokenId].vestExpiry) { // Mint the token to the founder _mint(tokenRecipient[baseTokenId].wallet, _tokenId); return true; // Else the founder has finished vesting: } else { // Remove them from future lookups delete tokenRecipient[baseTokenId]; return false; } } /// /// /// BURN /// /// /// /// @notice Burns a token that did not see any bids /// @param _tokenId The ERC-721 token id function burn(uint256 _tokenId) external { // Ensure the caller is the auction house if (msg.sender != settings.auction) { revert ONLY_AUCTION(); } // Burn the token _burn(_tokenId); } function _burn(uint256 _tokenId) internal override { super._burn(_tokenId); unchecked { --settings.totalSupply; } } /// /// /// METADATA /// /// /// /// @notice The URI for a token /// @param _tokenId The ERC-721 token id function tokenURI(uint256 _tokenId) public view override(IToken, ERC721) returns (string memory) { return settings.metadataRenderer.tokenURI(_tokenId); } /// @notice The URI for the contract function contractURI() public view override(IToken, ERC721) returns (string memory) { return settings.metadataRenderer.contractURI(); } /// /// /// FOUNDERS /// /// /// /// @notice The number of founders function totalFounders() external view returns (uint256) { return settings.numFounders; } /// @notice The founders total percent ownership function totalFounderOwnership() external view returns (uint256) { return settings.totalOwnership; } /// @notice The vesting details of a founder /// @param _founderId The founder id function getFounder(uint256 _founderId) external view returns (Founder memory) { return founder[_founderId]; } /// @notice The vesting details of all founders function getFounders() external view returns (Founder[] memory) { // Cache the number of founders uint256 numFounders = settings.numFounders; // Get a temporary array to hold all founders Founder[] memory founders = new Founder[](numFounders); // Cannot realistically overflow unchecked { // Add each founder to the array for (uint256 i; i < numFounders; ++i) { founders[i] = founder[i]; } } return founders; } /// @notice The founder scheduled to receive the given token id /// NOTE: If a founder is returned, there's no guarantee they'll receive the token as vesting expiration is not considered /// @param _tokenId The ERC-721 token id function getScheduledRecipient(uint256 _tokenId) external view returns (Founder memory) { return tokenRecipient[_tokenId % 100]; } /// @notice Update the list of allocation owners /// @param newFounders the full list of founders function updateFounders(IManager.FounderParams[] calldata newFounders) external onlyOwner { // Cache the number of founders uint256 numFounders = settings.numFounders; // Get a temporary array to hold all founders Founder[] memory cachedFounders = new Founder[](numFounders); // Cannot realistically overflow unchecked { // Add each founder to the array for (uint256 i; i < numFounders; ++i) { cachedFounders[i] = founder[i]; } } // Keep a mapping of all the reserved token IDs we're set to clear. bool[] memory clearedTokenIds = new bool[](100); unchecked { // for each existing founder: for (uint256 i; i < cachedFounders.length; ++i) { // copy the founder into memory Founder memory cachedFounder = cachedFounders[i]; // Delete the founder from the stored mapping delete founder[i]; // Some DAOs were initialized with 0 percentage ownership. // This skips them to avoid a division by zero error. if (cachedFounder.ownershipPct == 0) { continue; } // using the ownership percentage, get reserved token percentages uint256 schedule = 100 / cachedFounder.ownershipPct; // Used to reverse engineer the indices the founder has reserved tokens in. uint256 baseTokenId; for (uint256 j; j < cachedFounder.ownershipPct; ++j) { // Get the next index that hasn't already been cleared while (clearedTokenIds[baseTokenId] != false) { baseTokenId = (++baseTokenId) % 100; } delete tokenRecipient[baseTokenId]; clearedTokenIds[baseTokenId] = true; emit MintUnscheduled(baseTokenId, i, cachedFounder); // Update the base token id baseTokenId = (baseTokenId + schedule) % 100; } } } settings.numFounders = 0; settings.totalOwnership = 0; emit FounderAllocationsCleared(newFounders); _addFounders(newFounders); } /// /// /// SETTINGS /// /// /// /// @notice The total supply of tokens function totalSupply() external view returns (uint256) { return settings.totalSupply; } /// @notice The address of the auction house function auction() external view returns (address) { return settings.auction; } /// @notice The address of the metadata renderer function metadataRenderer() external view returns (address) { return address(settings.metadataRenderer); } function owner() public view override(IToken, Ownable) returns (address) { return super.owner(); } /// /// /// TOKEN UPGRADE /// /// /// /// @notice Ensures the caller is authorized to upgrade the contract and that the new implementation is valid /// @dev This function is called in `upgradeTo` & `upgradeToAndCall` /// @param _newImpl The new implementation address function _authorizeUpgrade(address _newImpl) internal view override { // Ensure the caller is the shared owner of the token and metadata renderer if (msg.sender != owner()) revert ONLY_OWNER(); // Ensure the implementation is valid if (!manager.isRegisteredUpgrade(_getImplementation(), _newImpl)) revert INVALID_UPGRADE(_newImpl); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.5.0) (interfaces/draft-IERC1822.sol) pragma solidity ^0.8.0; /** * @dev ERC1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified * proxy whose upgrades are fully controlled by the current implementation. */ interface IERC1822Proxiable { /** * @dev Returns the storage slot that the proxiable contract assumes is being used to store the implementation * address. * * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this * function revert if invoked through a proxy. */ function proxiableUUID() external view returns (bytes32); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (utils/StorageSlot.sol) pragma solidity ^0.8.0; /** * @dev Library for reading and writing primitive types to specific storage slots. * * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts. * This library helps with reading and writing to such slots without the need for inline assembly. * * The functions in this library return Slot structs that contain a `value` member that can be used to read or write. * * Example usage to set ERC1967 implementation slot: * ``` * contract ERC1967 { * bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; * * function _getImplementation() internal view returns (address) { * return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value; * } * * function _setImplementation(address newImplementation) internal { * require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract"); * StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation; * } * } * ``` * * _Available since v4.1 for `address`, `bool`, `bytes32`, and `uint256`._ */ library StorageSlot { struct AddressSlot { address value; } struct BooleanSlot { bool value; } struct Bytes32Slot { bytes32 value; } struct Uint256Slot { uint256 value; } /** * @dev Returns an `AddressSlot` with member `value` located at `slot`. */ function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `BooleanSlot` with member `value` located at `slot`. */ function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `Bytes32Slot` with member `value` located at `slot`. */ function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `Uint256Slot` with member `value` located at `slot`. */ function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.16; abstract contract VersionedContract { function contractVersion() external pure returns (string memory) { return "1.1.0"; } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.16; import { IUUPS } from "../lib/interfaces/IUUPS.sol"; import { IOwnable } from "../lib/interfaces/IOwnable.sol"; import { IPausable } from "../lib/interfaces/IPausable.sol"; /// @title IAuction /// @author Rohan Kulkarni /// @notice The external Auction events, errors, and functions interface IAuction is IUUPS, IOwnable, IPausable { /// /// /// EVENTS /// /// /// /// @notice Emitted when a bid is placed /// @param tokenId The ERC-721 token id /// @param bidder The address of the bidder /// @param amount The amount of ETH /// @param extended If the bid extended the auction /// @param endTime The end time of the auction event AuctionBid(uint256 tokenId, address bidder, uint256 amount, bool extended, uint256 endTime); /// @notice Emitted when an auction is settled /// @param tokenId The ERC-721 token id of the settled auction /// @param winner The address of the winning bidder /// @param amount The amount of ETH raised from the winning bid event AuctionSettled(uint256 tokenId, address winner, uint256 amount); /// @notice Emitted when an auction is created /// @param tokenId The ERC-721 token id of the created auction /// @param startTime The start time of the created auction /// @param endTime The end time of the created auction event AuctionCreated(uint256 tokenId, uint256 startTime, uint256 endTime); /// @notice Emitted when the auction duration is updated /// @param duration The new auction duration event DurationUpdated(uint256 duration); /// @notice Emitted when the reserve price is updated /// @param reservePrice The new reserve price event ReservePriceUpdated(uint256 reservePrice); /// @notice Emitted when the min bid increment percentage is updated /// @param minBidIncrementPercentage The new min bid increment percentage event MinBidIncrementPercentageUpdated(uint256 minBidIncrementPercentage); /// @notice Emitted when the time buffer is updated /// @param timeBuffer The new time buffer event TimeBufferUpdated(uint256 timeBuffer); /// /// /// ERRORS /// /// /// /// @dev Reverts if a bid is placed for the wrong token error INVALID_TOKEN_ID(); /// @dev Reverts if a bid is placed for an auction thats over error AUCTION_OVER(); /// @dev Reverts if a bid is placed for an auction that hasn't started error AUCTION_NOT_STARTED(); /// @dev Reverts if attempting to settle an active auction error AUCTION_ACTIVE(); /// @dev Reverts if attempting to settle an auction that was already settled error AUCTION_SETTLED(); /// @dev Reverts if a bid does not meet the reserve price error RESERVE_PRICE_NOT_MET(); /// @dev Reverts if a bid does not meet the minimum bid error MINIMUM_BID_NOT_MET(); /// @dev Error for when the bid increment is set to 0. error MIN_BID_INCREMENT_1_PERCENT(); /// @dev Reverts if the contract does not have enough ETH error INSOLVENT(); /// @dev Reverts if the caller was not the contract manager error ONLY_MANAGER(); /// @dev Thrown if the WETH contract throws a failure on transfer error FAILING_WETH_TRANSFER(); /// @dev Thrown if the auction creation failed error AUCTION_CREATE_FAILED_TO_LAUNCH(); /// /// /// FUNCTIONS /// /// /// /// @notice Initializes a DAO's auction house /// @param token The ERC-721 token address /// @param founder The founder responsible for starting the first auction /// @param treasury The treasury address where ETH will be sent /// @param duration The duration of each auction /// @param reservePrice The reserve price of each auction function initialize( address token, address founder, address treasury, uint256 duration, uint256 reservePrice ) external; /// @notice Creates a bid for the current token /// @param tokenId The ERC-721 token id function createBid(uint256 tokenId) external payable; /// @notice Settles the current auction and creates the next one function settleCurrentAndCreateNewAuction() external; /// @notice Settles the latest auction when the contract is paused function settleAuction() external; /// @notice Pauses the auction house function pause() external; /// @notice Unpauses the auction house function unpause() external; /// @notice The time duration of each auction function duration() external view returns (uint256); /// @notice The reserve price of each auction function reservePrice() external view returns (uint256); /// @notice The minimum amount of time to place a bid during an active auction function timeBuffer() external view returns (uint256); /// @notice The minimum percentage an incoming bid must raise the highest bid function minBidIncrement() external view returns (uint256); /// @notice Updates the time duration of each auction /// @param duration The new time duration function setDuration(uint256 duration) external; /// @notice Updates the reserve price of each auction /// @param reservePrice The new reserve price function setReservePrice(uint256 reservePrice) external; /// @notice Updates the time buffer of each auction /// @param timeBuffer The new time buffer function setTimeBuffer(uint256 timeBuffer) external; /// @notice Updates the minimum bid increment of each subsequent bid /// @param percentage The new percentage function setMinimumBidIncrement(uint256 percentage) external; /// @notice Get the address of the treasury function treasury() external returns (address); }
// SPDX-License-Identifier: MIT pragma solidity 0.8.16; /// @title IEIP712 /// @author Rohan Kulkarni /// @notice The external EIP712 errors and functions interface IEIP712 { /// /// /// ERRORS /// /// /// /// @dev Reverts if the deadline has passed to submit a signature error EXPIRED_SIGNATURE(); /// @dev Reverts if the recovered signature is invalid error INVALID_SIGNATURE(); /// /// /// FUNCTIONS /// /// /// /// @notice The sig nonce for an account /// @param account The account address function nonce(address account) external view returns (uint256); /// @notice The EIP-712 domain separator function DOMAIN_SEPARATOR() external view returns (bytes32); }
// SPDX-License-Identifier: MIT pragma solidity 0.8.16; /// @title IERC1967Upgrade /// @author Rohan Kulkarni /// @notice The external ERC1967Upgrade events and errors interface IERC1967Upgrade { /// /// /// EVENTS /// /// /// /// @notice Emitted when the implementation is upgraded /// @param impl The address of the implementation event Upgraded(address impl); /// /// /// ERRORS /// /// /// /// @dev Reverts if an implementation is an invalid upgrade /// @param impl The address of the invalid implementation error INVALID_UPGRADE(address impl); /// @dev Reverts if an implementation upgrade is not stored at the storage slot of the original error UNSUPPORTED_UUID(); /// @dev Reverts if an implementation does not support ERC1822 proxiableUUID() error ONLY_UUPS(); }
// SPDX-License-Identifier: MIT pragma solidity 0.8.16; /// @title IERC721 /// @author Rohan Kulkarni /// @notice The external ERC721 events, errors, and functions interface IERC721 { /// /// /// EVENTS /// /// /// /// @notice Emitted when a token is transferred from sender to recipient /// @param from The sender address /// @param to The recipient address /// @param tokenId The ERC-721 token id event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); /// @notice Emitted when an owner approves an account to manage a token /// @param owner The owner address /// @param approved The account address /// @param tokenId The ERC-721 token id event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); /// @notice Emitted when an owner sets an approval for a spender to manage all tokens /// @param owner The owner address /// @param operator The spender address /// @param approved If the approval is being set or removed event ApprovalForAll(address indexed owner, address indexed operator, bool approved); /// /// /// ERRORS /// /// /// /// @dev Reverts if a caller is not authorized to approve or transfer a token error INVALID_APPROVAL(); /// @dev Reverts if a transfer is called with the incorrect token owner error INVALID_OWNER(); /// @dev Reverts if a transfer is attempted to address(0) error INVALID_RECIPIENT(); /// @dev Reverts if an existing token is called to be minted error ALREADY_MINTED(); /// @dev Reverts if a non-existent token is called to be burned error NOT_MINTED(); /// /// /// FUNCTIONS /// /// /// /// @notice The number of tokens owned /// @param owner The owner address function balanceOf(address owner) external view returns (uint256); /// @notice The owner of a token /// @param tokenId The ERC-721 token id function ownerOf(uint256 tokenId) external view returns (address); /// @notice The account approved to manage a token /// @param tokenId The ERC-721 token id function getApproved(uint256 tokenId) external view returns (address); /// @notice If an operator is authorized to manage all of an owner's tokens /// @param owner The owner address /// @param operator The operator address function isApprovedForAll(address owner, address operator) external view returns (bool); /// @notice Authorizes an account to manage a token /// @param to The account address /// @param tokenId The ERC-721 token id function approve(address to, uint256 tokenId) external; /// @notice Authorizes an account to manage all tokens /// @param operator The account address /// @param approved If permission is being given or removed function setApprovalForAll(address operator, bool approved) external; /// @notice Safe transfers a token from sender to recipient with additional data /// @param from The sender address /// @param to The recipient address /// @param tokenId The ERC-721 token id /// @param data The additional data sent in the call to the recipient function safeTransferFrom( address from, address to, uint256 tokenId, bytes calldata data ) external; /// @notice Safe transfers a token from sender to recipient /// @param from The sender address /// @param to The recipient address /// @param tokenId The ERC-721 token id function safeTransferFrom( address from, address to, uint256 tokenId ) external; /// @notice Transfers a token from sender to recipient /// @param from The sender address /// @param to The recipient address /// @param tokenId The ERC-721 token id function transferFrom( address from, address to, uint256 tokenId ) external; }
// SPDX-License-Identifier: MIT pragma solidity 0.8.16; import { IERC721 } from "./IERC721.sol"; import { IEIP712 } from "./IEIP712.sol"; /// @title IERC721Votes /// @author Rohan Kulkarni /// @notice The external ERC721Votes events, errors, and functions interface IERC721Votes is IERC721, IEIP712 { /// /// /// EVENTS /// /// /// /// @notice Emitted when an account changes their delegate event DelegateChanged(address indexed delegator, address indexed from, address indexed to); /// @notice Emitted when a delegate's number of votes is updated event DelegateVotesChanged(address indexed delegate, uint256 prevTotalVotes, uint256 newTotalVotes); /// /// /// ERRORS /// /// /// /// @dev Reverts if the timestamp provided isn't in the past error INVALID_TIMESTAMP(); /// /// /// STRUCTS /// /// /// /// @notice The checkpoint data type /// @param timestamp The recorded timestamp /// @param votes The voting weight struct Checkpoint { uint64 timestamp; uint192 votes; } /// /// /// FUNCTIONS /// /// /// /// @notice The current number of votes for an account /// @param account The account address function getVotes(address account) external view returns (uint256); /// @notice The number of votes for an account at a past timestamp /// @param account The account address /// @param timestamp The past timestamp function getPastVotes(address account, uint256 timestamp) external view returns (uint256); /// @notice The delegate for an account /// @param account The account address function delegates(address account) external view returns (address); /// @notice Delegates votes to an account /// @param to The address delegating votes to function delegate(address to) external; /// @notice Delegates votes from a signer to an account /// @param from The address delegating votes from /// @param to The address delegating votes to /// @param deadline The signature deadline /// @param v The 129th byte and chain id of the signature /// @param r The first 64 bytes of the signature /// @param s Bytes 64-128 of the signature function delegateBySig( address from, address to, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external; }
// SPDX-License-Identifier: MIT pragma solidity 0.8.16; /// @title IInitializable /// @author Rohan Kulkarni /// @notice The external Initializable events and errors interface IInitializable { /// /// /// EVENTS /// /// /// /// @notice Emitted when the contract has been initialized or reinitialized event Initialized(uint256 version); /// /// /// ERRORS /// /// /// /// @dev Reverts if incorrectly initialized with address(0) error ADDRESS_ZERO(); /// @dev Reverts if disabling initializers during initialization error INITIALIZING(); /// @dev Reverts if calling an initialization function outside of initialization error NOT_INITIALIZING(); /// @dev Reverts if reinitializing incorrectly error ALREADY_INITIALIZED(); }
// SPDX-License-Identifier: MIT pragma solidity 0.8.16; /// @title IOwnable /// @author Rohan Kulkarni /// @notice The external Ownable events, errors, and functions interface IOwnable { /// /// /// EVENTS /// /// /// /// @notice Emitted when ownership has been updated /// @param prevOwner The previous owner address /// @param newOwner The new owner address event OwnerUpdated(address indexed prevOwner, address indexed newOwner); /// @notice Emitted when an ownership transfer is pending /// @param owner The current owner address /// @param pendingOwner The pending new owner address event OwnerPending(address indexed owner, address indexed pendingOwner); /// @notice Emitted when a pending ownership transfer has been canceled /// @param owner The current owner address /// @param canceledOwner The canceled owner address event OwnerCanceled(address indexed owner, address indexed canceledOwner); /// /// /// ERRORS /// /// /// /// @dev Reverts if an unauthorized user calls an owner function error ONLY_OWNER(); /// @dev Reverts if an unauthorized user calls a pending owner function error ONLY_PENDING_OWNER(); /// /// /// FUNCTIONS /// /// /// /// @notice The address of the owner function owner() external view returns (address); /// @notice The address of the pending owner function pendingOwner() external view returns (address); /// @notice Forces an ownership transfer /// @param newOwner The new owner address function transferOwnership(address newOwner) external; /// @notice Initiates a two-step ownership transfer /// @param newOwner The new owner address function safeTransferOwnership(address newOwner) external; /// @notice Accepts an ownership transfer function acceptOwnership() external; /// @notice Cancels a pending ownership transfer function cancelOwnershipTransfer() external; }
// SPDX-License-Identifier: MIT pragma solidity 0.8.16; /// @title IPausable /// @author Rohan Kulkarni /// @notice The external Pausable events, errors, and functions interface IPausable { /// /// /// EVENTS /// /// /// /// @notice Emitted when the contract is paused /// @param user The address that paused the contract event Paused(address user); /// @notice Emitted when the contract is unpaused /// @param user The address that unpaused the contract event Unpaused(address user); /// /// /// ERRORS /// /// /// /// @dev Reverts if called when the contract is paused error PAUSED(); /// @dev Reverts if called when the contract is unpaused error UNPAUSED(); /// /// /// FUNCTIONS /// /// /// /// @notice If the contract is paused function paused() external view returns (bool); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.16; import { IERC1822Proxiable } from "@openzeppelin/contracts/interfaces/draft-IERC1822.sol"; import { IERC1967Upgrade } from "./IERC1967Upgrade.sol"; /// @title IUUPS /// @author Rohan Kulkarni /// @notice The external UUPS errors and functions interface IUUPS is IERC1967Upgrade, IERC1822Proxiable { /// /// /// ERRORS /// /// /// /// @dev Reverts if not called directly error ONLY_CALL(); /// @dev Reverts if not called via delegatecall error ONLY_DELEGATECALL(); /// @dev Reverts if not called via proxy error ONLY_PROXY(); /// /// /// FUNCTIONS /// /// /// /// @notice Upgrades to an implementation /// @param newImpl The new implementation address function upgradeTo(address newImpl) external; /// @notice Upgrades to an implementation with an additional function call /// @param newImpl The new implementation address /// @param data The encoded function call function upgradeToAndCall(address newImpl, bytes memory data) external payable; }
// SPDX-License-Identifier: MIT pragma solidity 0.8.16; import { IERC1822Proxiable } from "@openzeppelin/contracts/interfaces/draft-IERC1822.sol"; import { StorageSlot } from "@openzeppelin/contracts/utils/StorageSlot.sol"; import { IERC1967Upgrade } from "../interfaces/IERC1967Upgrade.sol"; import { Address } from "../utils/Address.sol"; /// @title ERC1967Upgrade /// @author Rohan Kulkarni /// @notice Modified from OpenZeppelin Contracts v4.7.3 (proxy/ERC1967/ERC1967Upgrade.sol) /// - Uses custom errors declared in IERC1967Upgrade /// - Removes ERC1967 admin and beacon support abstract contract ERC1967Upgrade is IERC1967Upgrade { /// /// /// CONSTANTS /// /// /// /// @dev bytes32(uint256(keccak256('eip1967.proxy.rollback')) - 1) bytes32 private constant _ROLLBACK_SLOT = 0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143; /// @dev bytes32(uint256(keccak256('eip1967.proxy.implementation')) - 1) bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; /// /// /// FUNCTIONS /// /// /// /// @dev Upgrades to an implementation with security checks for UUPS proxies and an additional function call /// @param _newImpl The new implementation address /// @param _data The encoded function call function _upgradeToAndCallUUPS( address _newImpl, bytes memory _data, bool _forceCall ) internal { if (StorageSlot.getBooleanSlot(_ROLLBACK_SLOT).value) { _setImplementation(_newImpl); } else { try IERC1822Proxiable(_newImpl).proxiableUUID() returns (bytes32 slot) { if (slot != _IMPLEMENTATION_SLOT) revert UNSUPPORTED_UUID(); } catch { revert ONLY_UUPS(); } _upgradeToAndCall(_newImpl, _data, _forceCall); } } /// @dev Upgrades to an implementation with an additional function call /// @param _newImpl The new implementation address /// @param _data The encoded function call function _upgradeToAndCall( address _newImpl, bytes memory _data, bool _forceCall ) internal { _upgradeTo(_newImpl); if (_data.length > 0 || _forceCall) { Address.functionDelegateCall(_newImpl, _data); } } /// @dev Performs an implementation upgrade /// @param _newImpl The new implementation address function _upgradeTo(address _newImpl) internal { _setImplementation(_newImpl); emit Upgraded(_newImpl); } /// @dev Stores the address of an implementation /// @param _impl The implementation address function _setImplementation(address _impl) private { if (!Address.isContract(_impl)) revert INVALID_UPGRADE(_impl); StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = _impl; } /// @dev The address of the current implementation function _getImplementation() internal view returns (address) { return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value; } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.16; import { IUUPS } from "../interfaces/IUUPS.sol"; import { ERC1967Upgrade } from "./ERC1967Upgrade.sol"; /// @title UUPS /// @author Rohan Kulkarni /// @notice Modified from OpenZeppelin Contracts v4.7.3 (proxy/utils/UUPSUpgradeable.sol) /// - Uses custom errors declared in IUUPS /// - Inherits a modern, minimal ERC1967Upgrade abstract contract UUPS is IUUPS, ERC1967Upgrade { /// /// /// IMMUTABLES /// /// /// /// @dev The address of the implementation address private immutable __self = address(this); /// /// /// MODIFIERS /// /// /// /// @dev Ensures that execution is via proxy delegatecall with the correct implementation modifier onlyProxy() { if (address(this) == __self) revert ONLY_DELEGATECALL(); if (_getImplementation() != __self) revert ONLY_PROXY(); _; } /// @dev Ensures that execution is via direct call modifier notDelegated() { if (address(this) != __self) revert ONLY_CALL(); _; } /// /// /// FUNCTIONS /// /// /// /// @dev Hook to authorize an implementation upgrade /// @param _newImpl The new implementation address function _authorizeUpgrade(address _newImpl) internal virtual; /// @notice Upgrades to an implementation /// @param _newImpl The new implementation address function upgradeTo(address _newImpl) external onlyProxy { _authorizeUpgrade(_newImpl); _upgradeToAndCallUUPS(_newImpl, "", false); } /// @notice Upgrades to an implementation with an additional function call /// @param _newImpl The new implementation address /// @param _data The encoded function call function upgradeToAndCall(address _newImpl, bytes memory _data) external payable onlyProxy { _authorizeUpgrade(_newImpl); _upgradeToAndCallUUPS(_newImpl, _data, true); } /// @notice The storage slot of the implementation address function proxiableUUID() external view notDelegated returns (bytes32) { return _IMPLEMENTATION_SLOT; } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.16; import { IERC721 } from "../interfaces/IERC721.sol"; import { Initializable } from "../utils/Initializable.sol"; import { ERC721TokenReceiver } from "../utils/TokenReceiver.sol"; import { Address } from "../utils/Address.sol"; /// @title ERC721 /// @author Rohan Kulkarni /// @notice Modified from OpenZeppelin Contracts v4.7.3 (token/ERC721/ERC721Upgradeable.sol) /// - Uses custom errors declared in IERC721 abstract contract ERC721 is IERC721, Initializable { /// /// /// STORAGE /// /// /// /// @notice The token name string public name; /// @notice The token symbol string public symbol; /// @notice The token owners /// @dev ERC-721 token id => Owner mapping(uint256 => address) internal owners; /// @notice The owner balances /// @dev Owner => Balance mapping(address => uint256) internal balances; /// @notice The token approvals /// @dev ERC-721 token id => Manager mapping(uint256 => address) internal tokenApprovals; /// @notice The balance approvals /// @dev Owner => Operator => Approved mapping(address => mapping(address => bool)) internal operatorApprovals; /// /// /// FUNCTIONS /// /// /// /// @dev Initializes an ERC-721 token /// @param _name The ERC-721 token name /// @param _symbol The ERC-721 token symbol function __ERC721_init(string memory _name, string memory _symbol) internal onlyInitializing { name = _name; symbol = _symbol; } /// @notice The token URI /// @param _tokenId The ERC-721 token id function tokenURI(uint256 _tokenId) public view virtual returns (string memory) {} /// @notice The contract URI function contractURI() public view virtual returns (string memory) {} /// @notice If the contract implements an interface /// @param _interfaceId The interface id function supportsInterface(bytes4 _interfaceId) external pure returns (bool) { return _interfaceId == 0x01ffc9a7 || // ERC165 Interface ID _interfaceId == 0x80ac58cd || // ERC721 Interface ID _interfaceId == 0x5b5e139f; // ERC721Metadata Interface ID } /// @notice The account approved to manage a token /// @param _tokenId The ERC-721 token id function getApproved(uint256 _tokenId) external view returns (address) { return tokenApprovals[_tokenId]; } /// @notice If an operator is authorized to manage all of an owner's tokens /// @param _owner The owner address /// @param _operator The operator address function isApprovedForAll(address _owner, address _operator) external view returns (bool) { return operatorApprovals[_owner][_operator]; } /// @notice The number of tokens owned /// @param _owner The owner address function balanceOf(address _owner) public view returns (uint256) { if (_owner == address(0)) revert ADDRESS_ZERO(); return balances[_owner]; } /// @notice The owner of a token /// @param _tokenId The ERC-721 token id function ownerOf(uint256 _tokenId) public view returns (address) { address owner = owners[_tokenId]; if (owner == address(0)) revert INVALID_OWNER(); return owner; } /// @notice Authorizes an account to manage a token /// @param _to The account address /// @param _tokenId The ERC-721 token id function approve(address _to, uint256 _tokenId) external { address owner = owners[_tokenId]; if (msg.sender != owner && !operatorApprovals[owner][msg.sender]) revert INVALID_APPROVAL(); tokenApprovals[_tokenId] = _to; emit Approval(owner, _to, _tokenId); } /// @notice Authorizes an account to manage all tokens /// @param _operator The account address /// @param _approved If permission is being given or removed function setApprovalForAll(address _operator, bool _approved) external { operatorApprovals[msg.sender][_operator] = _approved; emit ApprovalForAll(msg.sender, _operator, _approved); } /// @notice Transfers a token from sender to recipient /// @param _from The sender address /// @param _to The recipient address /// @param _tokenId The ERC-721 token id function transferFrom( address _from, address _to, uint256 _tokenId ) public { if (_from != owners[_tokenId]) revert INVALID_OWNER(); if (_to == address(0)) revert ADDRESS_ZERO(); if (msg.sender != _from && !operatorApprovals[_from][msg.sender] && msg.sender != tokenApprovals[_tokenId]) revert INVALID_APPROVAL(); _beforeTokenTransfer(_from, _to, _tokenId); unchecked { --balances[_from]; ++balances[_to]; } owners[_tokenId] = _to; delete tokenApprovals[_tokenId]; emit Transfer(_from, _to, _tokenId); _afterTokenTransfer(_from, _to, _tokenId); } /// @notice Safe transfers a token from sender to recipient /// @param _from The sender address /// @param _to The recipient address /// @param _tokenId The ERC-721 token id function safeTransferFrom( address _from, address _to, uint256 _tokenId ) external { transferFrom(_from, _to, _tokenId); if ( Address.isContract(_to) && ERC721TokenReceiver(_to).onERC721Received(msg.sender, _from, _tokenId, "") != ERC721TokenReceiver.onERC721Received.selector ) revert INVALID_RECIPIENT(); } /// @notice Safe transfers a token from sender to recipient with additional data /// @param _from The sender address /// @param _to The recipient address /// @param _tokenId The ERC-721 token id function safeTransferFrom( address _from, address _to, uint256 _tokenId, bytes calldata _data ) external { transferFrom(_from, _to, _tokenId); if ( Address.isContract(_to) && ERC721TokenReceiver(_to).onERC721Received(msg.sender, _from, _tokenId, _data) != ERC721TokenReceiver.onERC721Received.selector ) revert INVALID_RECIPIENT(); } /// @dev Mints a token to a recipient /// @param _to The recipient address /// @param _tokenId The ERC-721 token id function _mint(address _to, uint256 _tokenId) internal virtual { if (_to == address(0)) revert ADDRESS_ZERO(); if (owners[_tokenId] != address(0)) revert ALREADY_MINTED(); _beforeTokenTransfer(address(0), _to, _tokenId); unchecked { ++balances[_to]; } owners[_tokenId] = _to; emit Transfer(address(0), _to, _tokenId); _afterTokenTransfer(address(0), _to, _tokenId); } /// @dev Burns a token to a recipient /// @param _tokenId The ERC-721 token id function _burn(uint256 _tokenId) internal virtual { address owner = owners[_tokenId]; if (owner == address(0)) revert NOT_MINTED(); _beforeTokenTransfer(owner, address(0), _tokenId); unchecked { --balances[owner]; } delete owners[_tokenId]; delete tokenApprovals[_tokenId]; emit Transfer(owner, address(0), _tokenId); _afterTokenTransfer(owner, address(0), _tokenId); } /// @dev Hook called before a token transfer /// @param _from The sender address /// @param _to The recipient address /// @param _tokenId The ERC-721 token id function _beforeTokenTransfer( address _from, address _to, uint256 _tokenId ) internal virtual {} /// @dev Hook called after a token transfer /// @param _from The sender address /// @param _to The recipient address /// @param _tokenId The ERC-721 token id function _afterTokenTransfer( address _from, address _to, uint256 _tokenId ) internal virtual {} }
// SPDX-License-Identifier: MIT pragma solidity 0.8.16; import { IERC721Votes } from "../interfaces/IERC721Votes.sol"; import { ERC721 } from "../token/ERC721.sol"; import { EIP712 } from "../utils/EIP712.sol"; /// @title ERC721Votes /// @author Rohan Kulkarni /// @notice Modified from OpenZeppelin Contracts v4.7.3 (token/ERC721/extensions/draft-ERC721Votes.sol) & Nouns DAO ERC721Checkpointable.sol commit 2cbe6c7 - licensed under the BSD-3-Clause license. /// - Uses custom errors defined in IERC721Votes /// - Checkpoints are based on timestamps instead of block numbers /// - Tokens are self-delegated by default /// - The total number of votes is the token supply itself abstract contract ERC721Votes is IERC721Votes, EIP712, ERC721 { /// /// /// CONSTANTS /// /// /// /// @dev The EIP-712 typehash to delegate with a signature bytes32 internal constant DELEGATION_TYPEHASH = keccak256("Delegation(address from,address to,uint256 nonce,uint256 deadline)"); /// /// /// STORAGE /// /// /// /// @notice The delegate for an account /// @notice Account => Delegate mapping(address => address) internal delegation; /// @notice The number of checkpoints for an account /// @dev Account => Num Checkpoints mapping(address => uint256) internal numCheckpoints; /// @notice The checkpoint for an account /// @dev Account => Checkpoint Id => Checkpoint mapping(address => mapping(uint256 => Checkpoint)) internal checkpoints; /// /// /// VOTING WEIGHT /// /// /// /// @notice The current number of votes for an account /// @param _account The account address function getVotes(address _account) public view returns (uint256) { // Get the account's number of checkpoints uint256 nCheckpoints = numCheckpoints[_account]; // Cannot underflow as `nCheckpoints` is ensured to be greater than 0 if reached unchecked { // Return the number of votes at the latest checkpoint if applicable return nCheckpoints != 0 ? checkpoints[_account][nCheckpoints - 1].votes : 0; } } /// @notice The number of votes for an account at a past timestamp /// @param _account The account address /// @param _timestamp The past timestamp function getPastVotes(address _account, uint256 _timestamp) public view returns (uint256) { // Ensure the given timestamp is in the past if (_timestamp >= block.timestamp) revert INVALID_TIMESTAMP(); // Get the account's number of checkpoints uint256 nCheckpoints = numCheckpoints[_account]; // If there are none return 0 if (nCheckpoints == 0) return 0; // Get the account's checkpoints mapping(uint256 => Checkpoint) storage accountCheckpoints = checkpoints[_account]; unchecked { // Get the latest checkpoint id // Cannot underflow as `nCheckpoints` is ensured to be greater than 0 uint256 lastCheckpoint = nCheckpoints - 1; // If the latest checkpoint has a valid timestamp, return its number of votes if (accountCheckpoints[lastCheckpoint].timestamp <= _timestamp) return accountCheckpoints[lastCheckpoint].votes; // If the first checkpoint doesn't have a valid timestamp, return 0 if (accountCheckpoints[0].timestamp > _timestamp) return 0; // Otherwise, find a checkpoint with a valid timestamp // Use the latest id as the initial upper bound uint256 high = lastCheckpoint; uint256 low; uint256 middle; // Used to temporarily hold a checkpoint Checkpoint memory cp; // While a valid checkpoint is to be found: while (high > low) { // Find the id of the middle checkpoint middle = high - (high - low) / 2; // Get the middle checkpoint cp = accountCheckpoints[middle]; // If the timestamp is a match: if (cp.timestamp == _timestamp) { // Return the voting weight return cp.votes; // Else if the timestamp is before the one looking for: } else if (cp.timestamp < _timestamp) { // Update the lower bound low = middle; // Else update the upper bound } else { high = middle - 1; } } return accountCheckpoints[low].votes; } } /// /// /// DELEGATION /// /// /// /// @notice The delegate for an account /// @param _account The account address function delegates(address _account) public view returns (address) { address current = delegation[_account]; return current == address(0) ? _account : current; } /// @notice Delegates votes to an account /// @param _to The address delegating votes to function delegate(address _to) external { _delegate(msg.sender, _to); } /// @notice Delegates votes from a signer to an account /// @param _from The address delegating votes from /// @param _to The address delegating votes to /// @param _deadline The signature deadline /// @param _v The 129th byte and chain id of the signature /// @param _r The first 64 bytes of the signature /// @param _s Bytes 64-128 of the signature function delegateBySig( address _from, address _to, uint256 _deadline, uint8 _v, bytes32 _r, bytes32 _s ) external { // Ensure the signature has not expired if (block.timestamp > _deadline) revert EXPIRED_SIGNATURE(); // Used to store the digest bytes32 digest; // Cannot realistically overflow unchecked { // Compute the hash of the domain seperator with the typed delegation data digest = keccak256( abi.encodePacked("\x19\x01", DOMAIN_SEPARATOR(), keccak256(abi.encode(DELEGATION_TYPEHASH, _from, _to, nonces[_from]++, _deadline))) ); } // Recover the message signer address recoveredAddress = ecrecover(digest, _v, _r, _s); // Ensure the recovered signer is the voter if (recoveredAddress == address(0) || recoveredAddress != _from) revert INVALID_SIGNATURE(); // Update the delegate _delegate(_from, _to); } /// @dev Updates delegate addresses /// @param _from The address delegating votes from /// @param _to The address delegating votes to function _delegate(address _from, address _to) internal { // If address(0) is being delegated to, update the op as a self-delegate if (_to == address(0)) _to = _from; // Get the previous delegate address prevDelegate = delegates(_from); // Store the new delegate delegation[_from] = _to; emit DelegateChanged(_from, prevDelegate, _to); // Transfer voting weight from the previous delegate to the new delegate _moveDelegateVotes(prevDelegate, _to, balanceOf(_from)); } /// @dev Transfers voting weight /// @param _from The address delegating votes from /// @param _to The address delegating votes to /// @param _amount The number of votes delegating function _moveDelegateVotes( address _from, address _to, uint256 _amount ) internal { unchecked { // If voting weight is being transferred: if (_from != _to && _amount > 0) { // If this isn't a token mint: if (_from != address(0)) { // Get the sender's number of checkpoints uint256 newCheckpointId = numCheckpoints[_from]; // Used to store their previous checkpoint id uint256 prevCheckpointId; // Used to store their previous checkpoint's voting weight uint256 prevTotalVotes; // Used to store their previous checkpoint's timestamp uint256 prevTimestamp; // If this isn't the sender's first checkpoint: if (newCheckpointId != 0) { // Get their previous checkpoint's id prevCheckpointId = newCheckpointId - 1; // Get their previous checkpoint's voting weight prevTotalVotes = checkpoints[_from][prevCheckpointId].votes; // Get their previous checkpoint's timestamp prevTimestamp = checkpoints[_from][prevCheckpointId].timestamp; } // Update their voting weight _writeCheckpoint(_from, newCheckpointId, prevCheckpointId, prevTimestamp, prevTotalVotes, prevTotalVotes - _amount); } // If this isn't a token burn: if (_to != address(0)) { // Get the recipients's number of checkpoints uint256 nCheckpoints = numCheckpoints[_to]; // Used to store their previous checkpoint id uint256 prevCheckpointId; // Used to store their previous checkpoint's voting weight uint256 prevTotalVotes; // Used to store their previous checkpoint's timestamp uint256 prevTimestamp; // If this isn't the recipient's first checkpoint: if (nCheckpoints != 0) { // Get their previous checkpoint's id prevCheckpointId = nCheckpoints - 1; // Get their previous checkpoint's voting weight prevTotalVotes = checkpoints[_to][prevCheckpointId].votes; // Get their previous checkpoint's timestamp prevTimestamp = checkpoints[_to][prevCheckpointId].timestamp; } // Update their voting weight _writeCheckpoint(_to, nCheckpoints, prevCheckpointId, prevTimestamp, prevTotalVotes, prevTotalVotes + _amount); } } } } /// @dev Records a checkpoint /// @param _account The account address /// @param _newId The new checkpoint id /// @param _prevId The previous checkpoint id /// @param _prevTimestamp The previous checkpoint timestamp /// @param _prevTotalVotes The previous checkpoint voting weight /// @param _newTotalVotes The new checkpoint voting weight function _writeCheckpoint( address _account, uint256 _newId, uint256 _prevId, uint256 _prevTimestamp, uint256 _prevTotalVotes, uint256 _newTotalVotes ) private { unchecked { // If the new checkpoint is not the user's first AND has the timestamp of the previous checkpoint: if (_newId > 0 && _prevTimestamp == block.timestamp) { // Just update the previous checkpoint's votes checkpoints[_account][_prevId].votes = uint192(_newTotalVotes); // Else write a new checkpoint: } else { // Get the pointer to store the checkpoint Checkpoint storage checkpoint = checkpoints[_account][_newId]; // Store the new voting weight and the current time checkpoint.votes = uint192(_newTotalVotes); checkpoint.timestamp = uint64(block.timestamp); // Increment the account's number of checkpoints ++numCheckpoints[_account]; } emit DelegateVotesChanged(_account, _prevTotalVotes, _newTotalVotes); } } /// @dev Enables each NFT to equal 1 vote /// @param _from The token sender /// @param _to The token recipient /// @param _tokenId The ERC-721 token id function _afterTokenTransfer( address _from, address _to, uint256 _tokenId ) internal override { // Transfer 1 vote from the sender to the recipient _moveDelegateVotes(delegates(_from), delegates(_to), 1); super._afterTokenTransfer(_from, _to, _tokenId); } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.16; /// @title EIP712 /// @author Rohan Kulkarni /// @notice Modified from OpenZeppelin Contracts v4.7.3 (utils/Address.sol) /// - Uses custom errors `INVALID_TARGET()` & `DELEGATE_CALL_FAILED()` /// - Adds util converting address to bytes32 library Address { /// /// /// ERRORS /// /// /// /// @dev Reverts if the target of a delegatecall is not a contract error INVALID_TARGET(); /// @dev Reverts if a delegatecall has failed error DELEGATE_CALL_FAILED(); /// /// /// FUNCTIONS /// /// /// /// @dev Utility to convert an address to bytes32 function toBytes32(address _account) internal pure returns (bytes32) { return bytes32(uint256(uint160(_account)) << 96); } /// @dev If an address is a contract function isContract(address _account) internal view returns (bool rv) { assembly { rv := gt(extcodesize(_account), 0) } } /// @dev Performs a delegatecall on an address function functionDelegateCall(address _target, bytes memory _data) internal returns (bytes memory) { if (!isContract(_target)) revert INVALID_TARGET(); (bool success, bytes memory returndata) = _target.delegatecall(_data); return verifyCallResult(success, returndata); } /// @dev Verifies a delegatecall was successful function verifyCallResult(bool _success, bytes memory _returndata) internal pure returns (bytes memory) { if (_success) { return _returndata; } else { if (_returndata.length > 0) { assembly { let returndata_size := mload(_returndata) revert(add(32, _returndata), returndata_size) } } else { revert DELEGATE_CALL_FAILED(); } } } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.16; import { IEIP712 } from "../interfaces/IEIP712.sol"; import { Initializable } from "../utils/Initializable.sol"; /// @title EIP712 /// @author Rohan Kulkarni /// @notice Modified from OpenZeppelin Contracts v4.7.3 (utils/cryptography/draft-EIP712Upgradeable.sol) /// - Uses custom errors declared in IEIP712 /// - Caches `INITIAL_CHAIN_ID` and `INITIAL_DOMAIN_SEPARATOR` upon initialization /// - Adds mapping for account nonces abstract contract EIP712 is IEIP712, Initializable { /// /// /// CONSTANTS /// /// /// /// @dev The EIP-712 domain typehash bytes32 internal constant DOMAIN_TYPEHASH = keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"); /// /// /// STORAGE /// /// /// /// @notice The hash of the EIP-712 domain name bytes32 internal HASHED_NAME; /// @notice The hash of the EIP-712 domain version bytes32 internal HASHED_VERSION; /// @notice The domain separator computed upon initialization bytes32 internal INITIAL_DOMAIN_SEPARATOR; /// @notice The chain id upon initialization uint256 internal INITIAL_CHAIN_ID; /// @notice The account nonces /// @dev Account => Nonce mapping(address => uint256) internal nonces; /// /// /// FUNCTIONS /// /// /// /// @dev Initializes EIP-712 support /// @param _name The EIP-712 domain name /// @param _version The EIP-712 domain version function __EIP712_init(string memory _name, string memory _version) internal onlyInitializing { HASHED_NAME = keccak256(bytes(_name)); HASHED_VERSION = keccak256(bytes(_version)); INITIAL_CHAIN_ID = block.chainid; INITIAL_DOMAIN_SEPARATOR = _computeDomainSeparator(); } /// @notice The current nonce for an account /// @param _account The account address function nonce(address _account) external view returns (uint256) { return nonces[_account]; } /// @notice The EIP-712 domain separator function DOMAIN_SEPARATOR() public view returns (bytes32) { return block.chainid == INITIAL_CHAIN_ID ? INITIAL_DOMAIN_SEPARATOR : _computeDomainSeparator(); } /// @dev Computes the EIP-712 domain separator function _computeDomainSeparator() private view returns (bytes32) { return keccak256(abi.encode(DOMAIN_TYPEHASH, HASHED_NAME, HASHED_VERSION, block.chainid, address(this))); } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.16; import { IInitializable } from "../interfaces/IInitializable.sol"; import { Address } from "../utils/Address.sol"; /// @title Initializable /// @author Rohan Kulkarni /// @notice Modified from OpenZeppelin Contracts v4.7.3 (proxy/utils/Initializable.sol) /// - Uses custom errors declared in IInitializable abstract contract Initializable is IInitializable { /// /// /// STORAGE /// /// /// /// @dev Indicates the contract has been initialized uint8 internal _initialized; /// @dev Indicates the contract is being initialized bool internal _initializing; /// /// /// MODIFIERS /// /// /// /// @dev Ensures an initialization function is only called within an `initializer` or `reinitializer` function modifier onlyInitializing() { if (!_initializing) revert NOT_INITIALIZING(); _; } /// @dev Enables initializing upgradeable contracts modifier initializer() { bool isTopLevelCall = !_initializing; if ((!isTopLevelCall || _initialized != 0) && (Address.isContract(address(this)) || _initialized != 1)) revert ALREADY_INITIALIZED(); _initialized = 1; if (isTopLevelCall) { _initializing = true; } _; if (isTopLevelCall) { _initializing = false; emit Initialized(1); } } /// @dev Enables initializer versioning /// @param _version The version to set modifier reinitializer(uint8 _version) { if (_initializing || _initialized >= _version) revert ALREADY_INITIALIZED(); _initialized = _version; _initializing = true; _; _initializing = false; emit Initialized(_version); } /// /// /// FUNCTIONS /// /// /// /// @dev Prevents future initialization function _disableInitializers() internal virtual { if (_initializing) revert INITIALIZING(); if (_initialized < type(uint8).max) { _initialized = type(uint8).max; emit Initialized(type(uint8).max); } } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.16; import { IOwnable } from "../interfaces/IOwnable.sol"; import { Initializable } from "../utils/Initializable.sol"; /// @title Ownable /// @author Rohan Kulkarni /// @notice Modified from OpenZeppelin Contracts v4.7.3 (access/OwnableUpgradeable.sol) /// - Uses custom errors declared in IOwnable /// - Adds optional two-step ownership transfer (`safeTransferOwnership` + `acceptOwnership`) abstract contract Ownable is IOwnable, Initializable { /// /// /// STORAGE /// /// /// /// @dev The address of the owner address internal _owner; /// @dev The address of the pending owner address internal _pendingOwner; /// /// /// MODIFIERS /// /// /// /// @dev Ensures the caller is the owner modifier onlyOwner() { if (msg.sender != _owner) revert ONLY_OWNER(); _; } /// @dev Ensures the caller is the pending owner modifier onlyPendingOwner() { if (msg.sender != _pendingOwner) revert ONLY_PENDING_OWNER(); _; } /// /// /// FUNCTIONS /// /// /// /// @dev Initializes contract ownership /// @param _initialOwner The initial owner address function __Ownable_init(address _initialOwner) internal onlyInitializing { _owner = _initialOwner; emit OwnerUpdated(address(0), _initialOwner); } /// @notice The address of the owner function owner() public virtual view returns (address) { return _owner; } /// @notice The address of the pending owner function pendingOwner() public view returns (address) { return _pendingOwner; } /// @notice Forces an ownership transfer from the last owner /// @param _newOwner The new owner address function transferOwnership(address _newOwner) public onlyOwner { _transferOwnership(_newOwner); } /// @notice Forces an ownership transfer from any sender /// @param _newOwner New owner to transfer contract to /// @dev Ensure is called only from trusted internal code, no access control checks. function _transferOwnership(address _newOwner) internal { emit OwnerUpdated(_owner, _newOwner); _owner = _newOwner; if (_pendingOwner != address(0)) delete _pendingOwner; } /// @notice Initiates a two-step ownership transfer /// @param _newOwner The new owner address function safeTransferOwnership(address _newOwner) public onlyOwner { _pendingOwner = _newOwner; emit OwnerPending(_owner, _newOwner); } /// @notice Accepts an ownership transfer function acceptOwnership() public onlyPendingOwner { emit OwnerUpdated(_owner, msg.sender); _owner = _pendingOwner; delete _pendingOwner; } /// @notice Cancels a pending ownership transfer function cancelOwnershipTransfer() public onlyOwner { emit OwnerCanceled(_owner, _pendingOwner); delete _pendingOwner; } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.16; import { Initializable } from "../utils/Initializable.sol"; /// @notice Modified from OpenZeppelin Contracts v4.7.3 (security/ReentrancyGuardUpgradeable.sol) /// - Uses custom error `REENTRANCY()` abstract contract ReentrancyGuard is Initializable { /// /// /// STORAGE /// /// /// /// @dev Indicates a function has not been entered uint256 internal constant _NOT_ENTERED = 1; /// @dev Indicates a function has been entered uint256 internal constant _ENTERED = 2; /// @notice The reentrancy status of a function uint256 internal _status; /// /// /// ERRORS /// /// /// /// @dev Reverts if attempted reentrancy error REENTRANCY(); /// /// /// FUNCTIONS /// /// /// /// @dev Initializes the reentrancy guard function __ReentrancyGuard_init() internal onlyInitializing { _status = _NOT_ENTERED; } /// @dev Ensures a function cannot be reentered modifier nonReentrant() { if (_status == _ENTERED) revert REENTRANCY(); _status = _ENTERED; _; _status = _NOT_ENTERED; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /// @notice Modified from OpenZeppelin Contracts v4.7.3 (token/ERC721/utils/ERC721Holder.sol) abstract contract ERC721TokenReceiver { function onERC721Received( address, address, uint256, bytes calldata ) external virtual returns (bytes4) { return this.onERC721Received.selector; } } /// @notice Modified from OpenZeppelin Contracts v4.7.3 (token/ERC1155/utils/ERC1155Holder.sol) abstract contract ERC1155TokenReceiver { function onERC1155Received( address, address, uint256, uint256, bytes calldata ) external virtual returns (bytes4) { return this.onERC1155Received.selector; } function onERC1155BatchReceived( address, address, uint256[] calldata, uint256[] calldata, bytes calldata ) external virtual returns (bytes4) { return this.onERC1155BatchReceived.selector; } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.16; import { IUUPS } from "../lib/interfaces/IUUPS.sol"; import { IOwnable } from "../lib/interfaces/IOwnable.sol"; /// @title IManager /// @author Rohan Kulkarni /// @notice The external Manager events, errors, structs and functions interface IManager is IUUPS, IOwnable { /// /// /// EVENTS /// /// /// /// @notice Emitted when a DAO is deployed /// @param token The ERC-721 token address /// @param metadata The metadata renderer address /// @param auction The auction address /// @param treasury The treasury address /// @param governor The governor address event DAODeployed(address token, address metadata, address auction, address treasury, address governor); /// @notice Emitted when an upgrade is registered by the Builder DAO /// @param baseImpl The base implementation address /// @param upgradeImpl The upgrade implementation address event UpgradeRegistered(address baseImpl, address upgradeImpl); /// @notice Emitted when an upgrade is unregistered by the Builder DAO /// @param baseImpl The base implementation address /// @param upgradeImpl The upgrade implementation address event UpgradeRemoved(address baseImpl, address upgradeImpl); /// /// /// ERRORS /// /// /// /// @dev Reverts if at least one founder is not provided upon deploy error FOUNDER_REQUIRED(); /// /// /// STRUCTS /// /// /// /// @notice The founder parameters /// @param wallet The wallet address /// @param ownershipPct The percent ownership of the token /// @param vestExpiry The timestamp that vesting expires struct FounderParams { address wallet; uint256 ownershipPct; uint256 vestExpiry; } /// @notice DAO Version Information information struct struct DAOVersionInfo { string token; string metadata; string auction; string treasury; string governor; } /// @notice The ERC-721 token parameters /// @param initStrings The encoded token name, symbol, collection description, collection image uri, renderer base uri struct TokenParams { bytes initStrings; } /// @notice The auction parameters /// @param reservePrice The reserve price of each auction /// @param duration The duration of each auction struct AuctionParams { uint256 reservePrice; uint256 duration; } /// @notice The governance parameters /// @param timelockDelay The time delay to execute a queued transaction /// @param votingDelay The time delay to vote on a created proposal /// @param votingPeriod The time period to vote on a proposal /// @param proposalThresholdBps The basis points of the token supply required to create a proposal /// @param quorumThresholdBps The basis points of the token supply required to reach quorum /// @param vetoer The address authorized to veto proposals (address(0) if none desired) struct GovParams { uint256 timelockDelay; uint256 votingDelay; uint256 votingPeriod; uint256 proposalThresholdBps; uint256 quorumThresholdBps; address vetoer; } /// /// /// FUNCTIONS /// /// /// /// @notice The token implementation address function tokenImpl() external view returns (address); /// @notice The metadata renderer implementation address function metadataImpl() external view returns (address); /// @notice The auction house implementation address function auctionImpl() external view returns (address); /// @notice The treasury implementation address function treasuryImpl() external view returns (address); /// @notice The governor implementation address function governorImpl() external view returns (address); /// @notice Deploys a DAO with custom token, auction, and governance settings /// @param founderParams The DAO founder(s) /// @param tokenParams The ERC-721 token settings /// @param auctionParams The auction settings /// @param govParams The governance settings function deploy( FounderParams[] calldata founderParams, TokenParams calldata tokenParams, AuctionParams calldata auctionParams, GovParams calldata govParams ) external returns ( address token, address metadataRenderer, address auction, address treasury, address governor ); /// @notice A DAO's remaining contract addresses from its token address /// @param token The ERC-721 token address function getAddresses(address token) external returns ( address metadataRenderer, address auction, address treasury, address governor ); /// @notice If an implementation is registered by the Builder DAO as an optional upgrade /// @param baseImpl The base implementation address /// @param upgradeImpl The upgrade implementation address function isRegisteredUpgrade(address baseImpl, address upgradeImpl) external view returns (bool); /// @notice Called by the Builder DAO to offer opt-in implementation upgrades for all other DAOs /// @param baseImpl The base implementation address /// @param upgradeImpl The upgrade implementation address function registerUpgrade(address baseImpl, address upgradeImpl) external; /// @notice Called by the Builder DAO to remove an upgrade /// @param baseImpl The base implementation address /// @param upgradeImpl The upgrade implementation address function removeUpgrade(address baseImpl, address upgradeImpl) external; }
// SPDX-License-Identifier: MIT pragma solidity 0.8.16; import { IUUPS } from "../lib/interfaces/IUUPS.sol"; import { IERC721Votes } from "../lib/interfaces/IERC721Votes.sol"; import { IManager } from "../manager/IManager.sol"; import { TokenTypesV1 } from "./types/TokenTypesV1.sol"; /// @title IToken /// @author Rohan Kulkarni /// @notice The external Token events, errors and functions interface IToken is IUUPS, IERC721Votes, TokenTypesV1 { /// /// /// EVENTS /// /// /// /// @notice Emitted when a token is scheduled to be allocated /// @param baseTokenId The /// @param founderId The founder's id /// @param founder The founder's vesting details event MintScheduled(uint256 baseTokenId, uint256 founderId, Founder founder); /// @notice Emitted when a token allocation is unscheduled (removed) /// @param baseTokenId The token ID % 100 /// @param founderId The founder's id /// @param founder The founder's vesting details event MintUnscheduled(uint256 baseTokenId, uint256 founderId, Founder founder); /// @notice Emitted when a tokens founders are deleted from storage /// @param newFounders the list of founders event FounderAllocationsCleared(IManager.FounderParams[] newFounders); /// /// /// ERRORS /// /// /// /// @dev Reverts if the founder ownership exceeds 100 percent error INVALID_FOUNDER_OWNERSHIP(); /// @dev Reverts if the caller was not the auction contract error ONLY_AUCTION(); /// @dev Reverts if no metadata was generated upon mint error NO_METADATA_GENERATED(); /// @dev Reverts if the caller was not the contract manager error ONLY_MANAGER(); /// /// /// FUNCTIONS /// /// /// /// @notice Initializes a DAO's ERC-721 token /// @param founders The founding members to receive vesting allocations /// @param initStrings The encoded token and metadata initialization strings /// @param metadataRenderer The token's metadata renderer /// @param auction The token's auction house function initialize( IManager.FounderParams[] calldata founders, bytes calldata initStrings, address metadataRenderer, address auction, address initialOwner ) external; /// @notice Mints tokens to the auction house for bidding and handles founder vesting function mint() external returns (uint256 tokenId); /// @notice Burns a token that did not see any bids /// @param tokenId The ERC-721 token id function burn(uint256 tokenId) external; /// @notice The URI for a token /// @param tokenId The ERC-721 token id function tokenURI(uint256 tokenId) external view returns (string memory); /// @notice The URI for the contract function contractURI() external view returns (string memory); /// @notice The number of founders function totalFounders() external view returns (uint256); /// @notice The founders total percent ownership function totalFounderOwnership() external view returns (uint256); /// @notice The vesting details of a founder /// @param founderId The founder id function getFounder(uint256 founderId) external view returns (Founder memory); /// @notice The vesting details of all founders function getFounders() external view returns (Founder[] memory); /// @notice Update the list of allocation owners /// @param newFounders the full list of FounderParam structs function updateFounders(IManager.FounderParams[] calldata newFounders) external; /// @notice The founder scheduled to receive the given token id /// NOTE: If a founder is returned, there's no guarantee they'll receive the token as vesting expiration is not considered /// @param tokenId The ERC-721 token id function getScheduledRecipient(uint256 tokenId) external view returns (Founder memory); /// @notice The total supply of tokens function totalSupply() external view returns (uint256); /// @notice The token's auction house function auction() external view returns (address); /// @notice The token's metadata renderer function metadataRenderer() external view returns (address); /// @notice The owner of the token and metadata renderer function owner() external view returns (address); /// @notice Callback called by auction on first auction started to transfer ownership to treasury from founder function onFirstAuctionStarted() external; }
// SPDX-License-Identifier: MIT pragma solidity 0.8.16; import { IUUPS } from "../../../lib/interfaces/IUUPS.sol"; /// @title IBaseMetadata /// @author Rohan Kulkarni /// @notice The external Base Metadata errors and functions interface IBaseMetadata is IUUPS { /// /// /// ERRORS /// /// /// /// @dev Reverts if the caller was not the contract manager error ONLY_MANAGER(); /// /// /// FUNCTIONS /// /// /// /// @notice Initializes a DAO's token metadata renderer /// @param initStrings The encoded token and metadata initialization strings /// @param token The associated ERC-721 token address function initialize( bytes calldata initStrings, address token ) external; /// @notice Generates attributes for a token upon mint /// @param tokenId The ERC-721 token id function onMinted(uint256 tokenId) external returns (bool); /// @notice The token URI /// @param tokenId The ERC-721 token id function tokenURI(uint256 tokenId) external view returns (string memory); /// @notice The contract URI function contractURI() external view returns (string memory); /// @notice The associated ERC-721 token function token() external view returns (address); /// @notice Get metadata owner address function owner() external view returns (address); }
// SPDX-License-Identifier: MIT pragma solidity 0.8.16; import { TokenTypesV1 } from "../types/TokenTypesV1.sol"; /// @title TokenStorageV1 /// @author Rohan Kulkarni /// @notice The Token storage contract contract TokenStorageV1 is TokenTypesV1 { /// @notice The token settings Settings internal settings; /// @notice The vesting details of a founder /// @dev Founder id => Founder mapping(uint256 => Founder) internal founder; /// @notice The recipient of a token /// @dev ERC-721 token id => Founder mapping(uint256 => Founder) internal tokenRecipient; }
// SPDX-License-Identifier: MIT pragma solidity 0.8.16; import { IBaseMetadata } from "../metadata/interfaces/IBaseMetadata.sol"; /// @title TokenTypesV1 /// @author Rohan Kulkarni /// @notice The Token custom data types interface TokenTypesV1 { /// @notice The settings type /// @param auction The DAO auction house /// @param totalSupply The number of active tokens /// @param numFounders The number of vesting recipients /// @param metadatarenderer The token metadata renderer /// @param mintCount The number of minted tokens /// @param totalPercentage The total percentage owned by founders struct Settings { address auction; uint88 totalSupply; uint8 numFounders; IBaseMetadata metadataRenderer; uint88 mintCount; uint8 totalOwnership; } /// @notice The founder type /// @param wallet The address where tokens are sent /// @param ownershipPct The percentage of token ownership /// @param vestExpiry The timestamp when vesting ends struct Founder { address wallet; uint8 ownershipPct; uint32 vestExpiry; } }
{ "remappings": [ "@openzeppelin/=node_modules/@openzeppelin/", "ds-test/=node_modules/ds-test/src/", "forge-std/=node_modules/forge-std/src/", "micro-onchain-metadata-utils/=node_modules/micro-onchain-metadata-utils/src/", "sol-uriencode/=node_modules/sol-uriencode/", "sol2string/=node_modules/sol2string/" ], "optimizer": { "enabled": true, "runs": 500000 }, "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
Contract ABI
API[{"inputs":[{"internalType":"address","name":"_manager","type":"address"}],"stateMutability":"payable","type":"constructor"},{"inputs":[],"name":"ADDRESS_ZERO","type":"error"},{"inputs":[],"name":"ALREADY_INITIALIZED","type":"error"},{"inputs":[],"name":"ALREADY_MINTED","type":"error"},{"inputs":[],"name":"DELEGATE_CALL_FAILED","type":"error"},{"inputs":[],"name":"EXPIRED_SIGNATURE","type":"error"},{"inputs":[],"name":"INITIALIZING","type":"error"},{"inputs":[],"name":"INVALID_APPROVAL","type":"error"},{"inputs":[],"name":"INVALID_FOUNDER_OWNERSHIP","type":"error"},{"inputs":[],"name":"INVALID_OWNER","type":"error"},{"inputs":[],"name":"INVALID_RECIPIENT","type":"error"},{"inputs":[],"name":"INVALID_SIGNATURE","type":"error"},{"inputs":[],"name":"INVALID_TARGET","type":"error"},{"inputs":[],"name":"INVALID_TIMESTAMP","type":"error"},{"inputs":[{"internalType":"address","name":"impl","type":"address"}],"name":"INVALID_UPGRADE","type":"error"},{"inputs":[],"name":"NOT_INITIALIZING","type":"error"},{"inputs":[],"name":"NOT_MINTED","type":"error"},{"inputs":[],"name":"NO_METADATA_GENERATED","type":"error"},{"inputs":[],"name":"ONLY_AUCTION","type":"error"},{"inputs":[],"name":"ONLY_CALL","type":"error"},{"inputs":[],"name":"ONLY_DELEGATECALL","type":"error"},{"inputs":[],"name":"ONLY_MANAGER","type":"error"},{"inputs":[],"name":"ONLY_OWNER","type":"error"},{"inputs":[],"name":"ONLY_PENDING_OWNER","type":"error"},{"inputs":[],"name":"ONLY_PROXY","type":"error"},{"inputs":[],"name":"ONLY_UUPS","type":"error"},{"inputs":[],"name":"REENTRANCY","type":"error"},{"inputs":[],"name":"UNSUPPORTED_UUID","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"approved","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"delegator","type":"address"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"DelegateChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"delegate","type":"address"},{"indexed":false,"internalType":"uint256","name":"prevTotalVotes","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newTotalVotes","type":"uint256"}],"name":"DelegateVotesChanged","type":"event"},{"anonymous":false,"inputs":[{"components":[{"internalType":"address","name":"wallet","type":"address"},{"internalType":"uint256","name":"ownershipPct","type":"uint256"},{"internalType":"uint256","name":"vestExpiry","type":"uint256"}],"indexed":false,"internalType":"struct IManager.FounderParams[]","name":"newFounders","type":"tuple[]"}],"name":"FounderAllocationsCleared","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"version","type":"uint256"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"baseTokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"founderId","type":"uint256"},{"components":[{"internalType":"address","name":"wallet","type":"address"},{"internalType":"uint8","name":"ownershipPct","type":"uint8"},{"internalType":"uint32","name":"vestExpiry","type":"uint32"}],"indexed":false,"internalType":"struct TokenTypesV1.Founder","name":"founder","type":"tuple"}],"name":"MintScheduled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"baseTokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"founderId","type":"uint256"},{"components":[{"internalType":"address","name":"wallet","type":"address"},{"internalType":"uint8","name":"ownershipPct","type":"uint8"},{"internalType":"uint32","name":"vestExpiry","type":"uint32"}],"indexed":false,"internalType":"struct TokenTypesV1.Founder","name":"founder","type":"tuple"}],"name":"MintUnscheduled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"canceledOwner","type":"address"}],"name":"OwnerCanceled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"pendingOwner","type":"address"}],"name":"OwnerPending","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"prevOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnerUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"impl","type":"address"}],"name":"Upgraded","type":"event"},{"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"auction","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"burn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"cancelOwnershipTransfer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"contractURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"contractVersion","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"}],"name":"delegate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_deadline","type":"uint256"},{"internalType":"uint8","name":"_v","type":"uint8"},{"internalType":"bytes32","name":"_r","type":"bytes32"},{"internalType":"bytes32","name":"_s","type":"bytes32"}],"name":"delegateBySig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"delegates","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_founderId","type":"uint256"}],"name":"getFounder","outputs":[{"components":[{"internalType":"address","name":"wallet","type":"address"},{"internalType":"uint8","name":"ownershipPct","type":"uint8"},{"internalType":"uint32","name":"vestExpiry","type":"uint32"}],"internalType":"struct TokenTypesV1.Founder","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getFounders","outputs":[{"components":[{"internalType":"address","name":"wallet","type":"address"},{"internalType":"uint8","name":"ownershipPct","type":"uint8"},{"internalType":"uint32","name":"vestExpiry","type":"uint32"}],"internalType":"struct TokenTypesV1.Founder[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"},{"internalType":"uint256","name":"_timestamp","type":"uint256"}],"name":"getPastVotes","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"getScheduledRecipient","outputs":[{"components":[{"internalType":"address","name":"wallet","type":"address"},{"internalType":"uint8","name":"ownershipPct","type":"uint8"},{"internalType":"uint32","name":"vestExpiry","type":"uint32"}],"internalType":"struct TokenTypesV1.Founder","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"getVotes","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"wallet","type":"address"},{"internalType":"uint256","name":"ownershipPct","type":"uint256"},{"internalType":"uint256","name":"vestExpiry","type":"uint256"}],"internalType":"struct IManager.FounderParams[]","name":"_founders","type":"tuple[]"},{"internalType":"bytes","name":"_initStrings","type":"bytes"},{"internalType":"address","name":"_metadataRenderer","type":"address"},{"internalType":"address","name":"_auction","type":"address"},{"internalType":"address","name":"_initialOwner","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address","name":"_operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"metadataRenderer","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"mint","outputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"nonce","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"onFirstAuctionStarted","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"proxiableUUID","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_tokenId","type":"uint256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newOwner","type":"address"}],"name":"safeTransferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_operator","type":"address"},{"internalType":"bool","name":"_approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"_interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalFounderOwnership","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalFounders","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"wallet","type":"address"},{"internalType":"uint256","name":"ownershipPct","type":"uint256"},{"internalType":"uint256","name":"vestExpiry","type":"uint256"}],"internalType":"struct IManager.FounderParams[]","name":"newFounders","type":"tuple[]"}],"name":"updateFounders","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newImpl","type":"address"}],"name":"upgradeTo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newImpl","type":"address"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"upgradeToAndCall","outputs":[],"stateMutability":"payable","type":"function"}]
Contract Creation Code
60c060408190523060805262004e2f3881900390819083398101604081905262000029916200011c565b600054610100900460ff161580158062000047575060005460ff1615155b801562000077575062000065306200011660201b62002b3c1760201c565b8062000077575060005460ff16600114155b15620000965760405163439a74c960e01b815260040160405180910390fd5b6000805460ff191660011790558015620000ba576000805461ff0019166101001790555b6001600160a01b03821660a05280156200010e576000805461ff0019169055604051600181527fbe9b076dc5b65990cca9dd9d7366682482e7817a6f6bc7f4faf4dc32af497f329060200160405180910390a15b50506200014e565b3b151590565b6000602082840312156200012f57600080fd5b81516001600160a01b03811681146200014757600080fd5b9392505050565b60805160a051614c986200019760003960008181611a6f0152612e0201526000818161116a015281816111c401528181611777015281816117d101526118c40152614c986000f3fe6080604052600436106102e75760003560e01c806370a0823111610184578063b20d7fa9116100d6578063d9d3e0901161008a578063e8a3d48511610064578063e8a3d48514610988578063e985e9c51461099d578063f2fde38b146109f357600080fd5b8063d9d3e09014610902578063dc276e571461093d578063e30c39781461095d57600080fd5b8063b88d4fde116100bb578063b88d4fde146108a2578063c87b56dd146108c2578063d1bfda66146108e257600080fd5b8063b20d7fa914610860578063b73cdd191461088057600080fd5b80638da5cb5b116101385780639d8aefc2116101125780639d8aefc2146107e5578063a0a8e460146107fa578063a22cb4651461084057600080fd5b80638da5cb5b1461077f57806395d89b41146107b05780639ab24eb0146107c557600080fd5b806374fd46551161016957806374fd46551461070457806379ba50971461073f5780637d9f6db51461075457600080fd5b806370a08231146106a157806370ae92d2146106c157600080fd5b80633a46b1a81161023d57806352d1902d116101f15780636097bf62116101cb5780636097bf62146106365780636352211e14610656578063703199701461067657600080fd5b806352d1902d146105e1578063587cde1e146105f65780635c19a95c1461061657600080fd5b806342842e0e1161022257806342842e0e1461058e57806342966c68146105ae5780634f1ef286146105ce57600080fd5b80633a46b1a8146104b45780633bcb43f3146104d457600080fd5b806318160ddd1161029f5780633644e515116102795780633644e5151461045f5780633659cfe614610474578063395db2cd1461049457600080fd5b806318160ddd146103f057806323452b9c1461042a57806323b872dd1461043f57600080fd5b8063081812fc116102d0578063081812fc14610343578063095ea7b3146103ab5780631249c58b146103cd57600080fd5b806301ffc9a7146102ec57806306fdde0314610321575b600080fd5b3480156102f857600080fd5b5061030c610307366004614076565b610a13565b60405190151581526020015b60405180910390f35b34801561032d57600080fd5b50610336610af8565b60405161031891906140b7565b34801561034f57600080fd5b5061038661035e366004614108565b6000908152600c602052604090205473ffffffffffffffffffffffffffffffffffffffff1690565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610318565b3480156103b757600080fd5b506103cb6103c6366004614143565b610b86565b005b3480156103d957600080fd5b506103e2610ca4565b604051908152602001610318565b3480156103fc57600080fd5b506011547401000000000000000000000000000000000000000090046affffffffffffffffffffff166103e2565b34801561043657600080fd5b506103cb610db6565b34801561044b57600080fd5b506103cb61045a36600461416f565b610e88565b34801561046b57600080fd5b506103e26110d0565b34801561048057600080fd5b506103cb61048f3660046141b0565b611153565b3480156104a057600080fd5b506103cb6104af3660046141b0565b6112ab565b3480156104c057600080fd5b506103e26104cf366004614143565b61137f565b3480156104e057600080fd5b506105816104ef366004614108565b6040805160608082018352600080835260208084018290529284018190529384526013825292829020825193840183525473ffffffffffffffffffffffffffffffffffffffff8116845274010000000000000000000000000000000000000000810460ff16918401919091527501000000000000000000000000000000000000000000900463ffffffff169082015290565b60405161031891906141cd565b34801561059a57600080fd5b506103cb6105a936600461416f565b6115e3565b3480156105ba57600080fd5b506103cb6105c9366004614108565b611706565b6103cb6105dc36600461430f565b611760565b3480156105ed57600080fd5b506103e26118aa565b34801561060257600080fd5b506103866106113660046141b0565b611940565b34801561062257600080fd5b506103cb6106313660046141b0565b61197f565b34801561064257600080fd5b506103cb610651366004614401565b611989565b34801561066257600080fd5b50610386610671366004614108565b611bc6565b34801561068257600080fd5b5060125473ffffffffffffffffffffffffffffffffffffffff16610386565b3480156106ad57600080fd5b506103e26106bc3660046141b0565b611c22565b3480156106cd57600080fd5b506103e26106dc3660046141b0565b73ffffffffffffffffffffffffffffffffffffffff1660009081526007602052604090205490565b34801561071057600080fd5b506011547f0100000000000000000000000000000000000000000000000000000000000000900460ff166103e2565b34801561074b57600080fd5b506103cb611c9a565b34801561076057600080fd5b5060115473ffffffffffffffffffffffffffffffffffffffff16610386565b34801561078b57600080fd5b5060005462010000900473ffffffffffffffffffffffffffffffffffffffff16610386565b3480156107bc57600080fd5b50610336611da4565b3480156107d157600080fd5b506103e26107e03660046141b0565b611db1565b3480156107f157600080fd5b506103cb611e80565b34801561080657600080fd5b5060408051808201909152600581527f312e312e300000000000000000000000000000000000000000000000000000006020820152610336565b34801561084c57600080fd5b506103cb61085b3660046144b8565b611f6f565b34801561086c57600080fd5b506103cb61087b3660046144f1565b612006565b34801561088c57600080fd5b5061089561225b565b604051610318919061455c565b3480156108ae57600080fd5b506103cb6108bd3660046145dd565b6123c5565b3480156108ce57600080fd5b506103366108dd366004614108565b6124dd565b3480156108ee57600080fd5b506103cb6108fd366004614650565b612593565b34801561090e57600080fd5b506012547f0100000000000000000000000000000000000000000000000000000000000000900460ff166103e2565b34801561094957600080fd5b50610581610958366004614108565b612978565b34801561096957600080fd5b5060015473ffffffffffffffffffffffffffffffffffffffff16610386565b34801561099457600080fd5b50610336612a26565b3480156109a957600080fd5b5061030c6109b8366004614692565b73ffffffffffffffffffffffffffffffffffffffff9182166000908152600d6020908152604080832093909416825291909152205460ff1690565b3480156109ff57600080fd5b506103cb610a0e3660046141b0565b612adc565b60007f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff0000000000000000000000000000000000000000000000000000000083161480610aa657507f80ac58cd000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316145b80610af257507f5b5e139f000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316145b92915050565b60088054610b05906146c0565b80601f0160208091040260200160405190810160405280929190818152602001828054610b31906146c0565b8015610b7e5780601f10610b5357610100808354040283529160200191610b7e565b820191906000526020600020905b815481529060010190602001808311610b6157829003601f168201915b505050505081565b6000818152600a602052604090205473ffffffffffffffffffffffffffffffffffffffff16338114801590610bec575073ffffffffffffffffffffffffffffffffffffffff81166000908152600d6020908152604080832033845290915290205460ff16155b15610c23576040517f3201fe7300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000828152600c602052604080822080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff87811691821790925591518593918516917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591a4505050565b60006002805403610ce1576040517fad2ce74900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6002805560115473ffffffffffffffffffffffffffffffffffffffff16338114610d37576040517f3b30aafa00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b601280547fff0000000000000000000000ffffffffffffffffffffffffffffffffffffffff8116600174010000000000000000000000000000000000000000928390046affffffffffffffffffffff90811691820116909202179091559150610d9f82612b42565b610d3757610dad8183612c32565b50600160025590565b60005462010000900473ffffffffffffffffffffffffffffffffffffffff163314610e0d576040517fd238ed5900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001546000805460405173ffffffffffffffffffffffffffffffffffffffff9384169362010000909204909116917f682679deecef4dcd49674845cc1e3a075fea9073680aa445a8207d5a4bdea3da91a3600180547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055565b6000818152600a602052604090205473ffffffffffffffffffffffffffffffffffffffff848116911614610ee8576040517f9d2d273100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8216610f35576040517f66e7950900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3373ffffffffffffffffffffffffffffffffffffffff841614801590610f8c575073ffffffffffffffffffffffffffffffffffffffff83166000908152600d6020908152604080832033845290915290205460ff16155b8015610fbc57506000818152600c602052604090205473ffffffffffffffffffffffffffffffffffffffff163314155b15610ff3576040517f3201fe7300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8084166000818152600b6020908152604080832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01905593861680835284832080546001019055858352600a825284832080547fffffffffffffffffffffffff00000000000000000000000000000000000000009081168317909155600c90925284832080549092169091559251849392917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a46110cb838383612d61565b505050565b6000600654461461114c57611147600354600454604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60208201529081019290925260608201524660808201523060a082015260009060c00160405160208183030381529060405280519060200120905090565b905090565b5060055490565b73ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001630036111c2576040517f43d22ee900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166112377f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff1614611284576040517fe74d90a000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61128d81612d7d565b6112a881604051806020016040528060008152506000612f62565b50565b60005462010000900473ffffffffffffffffffffffffffffffffffffffff163314611302576040517fd238ed5900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff8381169182179092556000805460405192936201000090910416917f4f2638f5949b9614ef8d5e268cb51348ad7f434a34812bf64b6e95014fbd357e9190a350565b60004282106113ba576040517f118818d100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff83166000908152600f6020526040812054908190036113f2576000915050610af2565b73ffffffffffffffffffffffffffffffffffffffff841660009081526010602090815260408083207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff85018085529281905292205467ffffffffffffffff168510611496576000908152602091909152604090205468010000000000000000900477ffffffffffffffffffffffffffffffffffffffffffffffff169150610af29050565b60008080526020839052604090205467ffffffffffffffff168510156114c25760009350505050610af2565b60408051808201909152600080825260208201819052829181905b828411156115a05760028385030484036000818152602088815260409182902082518084019093525467ffffffffffffffff81168084526801000000000000000090910477ffffffffffffffffffffffffffffffffffffffffffffffff1691830191909152919350915089900361157a576020015177ffffffffffffffffffffffffffffffffffffffffffffffff169650610af295505050505050565b805167ffffffffffffffff16891115611595578192506114dd565b6001820393506114dd565b505060009081526020939093525050604090205468010000000000000000900477ffffffffffffffffffffffffffffffffffffffffffffffff1691505092915050565b6115ee838383610e88565b813b151580156116cf57506040517f150b7a020000000000000000000000000000000000000000000000000000000080825233600483015273ffffffffffffffffffffffffffffffffffffffff858116602484015260448301849052608060648401526000608484015290919084169063150b7a029060a4016020604051808303816000875af1158015611686573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116aa919061473c565b7fffffffff000000000000000000000000000000000000000000000000000000001614155b156110cb576040517f521005a600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60115473ffffffffffffffffffffffffffffffffffffffff163314611757576040517f3b30aafa00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6112a8816130b5565b73ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001630036117cf576040517f43d22ee900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166118447f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff1614611891576040517fe74d90a000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61189a82612d7d565b6118a682826001612f62565b5050565b60003073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000161461191b576040517f575bc92e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b507f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc90565b73ffffffffffffffffffffffffffffffffffffffff8082166000908152600e602052604081205490911680156119765780611978565b825b9392505050565b6112a8338261313a565b600054610100900460ff16158015806119a6575060005460ff1615155b80156119c25750303b1515806119c2575060005460ff16600114155b156119f9576040517f439a74c900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790558015611a5757600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614611ac6576040517fa2ddd97100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611ace6131f8565b611ad782613240565b611ae188886132f9565b600080611af087890189614779565b5050505091509150611b0282826136b8565b50506012805473ffffffffffffffffffffffffffffffffffffffff8087167fffffffffffffffffffffffff00000000000000000000000000000000000000009283161790925560118054928616929091169190911790558015611bbc57600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527fbe9b076dc5b65990cca9dd9d7366682482e7817a6f6bc7f4faf4dc32af497f329060200160405180910390a15b5050505050505050565b6000818152600a602052604081205473ffffffffffffffffffffffffffffffffffffffff1680610af2576040517f9d2d273100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff8216611c71576040517f66e7950900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5073ffffffffffffffffffffffffffffffffffffffff166000908152600b602052604090205490565b60015473ffffffffffffffffffffffffffffffffffffffff163314611ceb576040517f065cd53100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000805460405133926201000090920473ffffffffffffffffffffffffffffffffffffffff16917f8292fce18fa69edf4db7b94ea2e58241df0ae57f97e0a6c9b29067028bf92d7691a360018054600080547fffffffffffffffffffff0000000000000000000000000000000000000000ffff1673ffffffffffffffffffffffffffffffffffffffff831662010000021790557fffffffffffffffffffffffff0000000000000000000000000000000000000000169055565b60098054610b05906146c0565b73ffffffffffffffffffffffffffffffffffffffff81166000908152600f6020526040812054808203611de5576000611e5f565b73ffffffffffffffffffffffffffffffffffffffff831660009081526010602090815260408083207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8501845290915290205468010000000000000000900477ffffffffffffffffffffffffffffffffffffffffffffffff165b77ffffffffffffffffffffffffffffffffffffffffffffffff169392505050565b60115473ffffffffffffffffffffffffffffffffffffffff163314611ed1576040517f3b30aafa00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b601154604080517f61d027b30000000000000000000000000000000000000000000000000000000081529051611f6d9273ffffffffffffffffffffffffffffffffffffffff16916361d027b391600480830192602092919082900301816000875af1158015611f44573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f68919061486e565b613712565b565b336000818152600d6020908152604080832073ffffffffffffffffffffffffffffffffffffffff87168085529083529281902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001686151590811790915590519081529192917f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a35050565b83421115612040576040517f6ed6bef000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600061204a6110d0565b73ffffffffffffffffffffffffffffffffffffffff88811660008181526007602090815260409182902080546001810190915582517f9ba0adc65ac9b85f9640562bd298ef1e78f86fbfbc6433772a69f08b092c5b238184015280840194909452938b166060840152608083019390935260a08083018a90528151808403909101815260c0830190915280519201919091207f190100000000000000000000000000000000000000000000000000000000000060e083015260e282019290925261010281019190915261012201604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181528282528051602091820120600080855291840180845281905260ff88169284019290925260608301869052608083018590529092509060019060a0016020604051602081039080840390855afa1580156121a0573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015191505073ffffffffffffffffffffffffffffffffffffffff8116158061221a57508773ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614155b15612251576040517fa3402a3800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611bbc888861313a565b6011546060907f0100000000000000000000000000000000000000000000000000000000000000900460ff1660008167ffffffffffffffff8111156122a2576122a261420d565b60405190808252806020026020018201604052801561230b57816020015b60408051606081018252600080825260208083018290529282015282527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9092019101816122c05790505b50905060005b828110156123be576000818152601360209081526040918290208251606081018452905473ffffffffffffffffffffffffffffffffffffffff8116825274010000000000000000000000000000000000000000810460ff1692820192909252750100000000000000000000000000000000000000000090910463ffffffff169181019190915282518390839081106123ab576123ab61488b565b6020908102919091010152600101612311565b5092915050565b6123d0858585610e88565b833b1515801561249f57506040517f150b7a02000000000000000000000000000000000000000000000000000000008082529073ffffffffffffffffffffffffffffffffffffffff86169063150b7a02906124379033908a908990899089906004016148ba565b6020604051808303816000875af1158015612456573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061247a919061473c565b7fffffffff000000000000000000000000000000000000000000000000000000001614155b156124d6576040517f521005a600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5050505050565b6012546040517fc87b56dd0000000000000000000000000000000000000000000000000000000081526004810183905260609173ffffffffffffffffffffffffffffffffffffffff169063c87b56dd90602401600060405180830381865afa15801561254d573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052610af29190810190614939565b60005462010000900473ffffffffffffffffffffffffffffffffffffffff1633146125ea576040517fd238ed5900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6011547f0100000000000000000000000000000000000000000000000000000000000000900460ff1660008167ffffffffffffffff81111561262e5761262e61420d565b60405190808252806020026020018201604052801561269757816020015b60408051606081018252600080825260208083018290529282015282527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90920191018161264c5790505b50905060005b8281101561274a576000818152601360209081526040918290208251606081018452905473ffffffffffffffffffffffffffffffffffffffff8116825274010000000000000000000000000000000000000000810460ff1692820192909252750100000000000000000000000000000000000000000090910463ffffffff169181019190915282518390839081106127375761273761488b565b602090810291909101015260010161269d565b50604080516064808252610ca0820190925260009160208201610c808036833701905050905060005b82518110156129005760008382815181106127905761279061488b565b6020908102919091018101516000848152601383526040812080547fffffffffffffff000000000000000000000000000000000000000000000000001690559181015190925060ff1690036127e557506128f8565b6000816020015160ff166064816127fe576127fe61470d565b0460ff1690506000805b836020015160ff168110156128f3575b85828151811061282a5761282a61488b565b60209081029190910101511561284b57600190910190606482069150612818565b600082815260146020526040902080547fffffffffffffff0000000000000000000000000000000000000000000000000016905585516001908790849081106128965761289661488b565b6020026020010190151590811515815250507f6309c4a2f8a0b726702416b909c21dce80f888bf255698775cd12336acd16b958286866040516128db939291906149a7565b60405180910390a16064828401069150600101612808565b505050505b600101612773565b50601180547effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9081169091556012805490911690556040517f6fb4c002bf55855ac8dd687342fe82b08a0a20ea80a7588566bfc6703bae213f9061296690879087906149fd565b60405180910390a16124d685856132f9565b6040805160608101825260008082526020820181905291810191909152601460006129a4606485614a6d565b815260208082019290925260409081016000208151606081018352905473ffffffffffffffffffffffffffffffffffffffff8116825274010000000000000000000000000000000000000000810460ff1693820193909352750100000000000000000000000000000000000000000090920463ffffffff169082015292915050565b601254604080517fe8a3d485000000000000000000000000000000000000000000000000000000008152905160609273ffffffffffffffffffffffffffffffffffffffff169163e8a3d4859160048083019260009291908290030181865afa158015612a96573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526111479190810190614939565b60005462010000900473ffffffffffffffffffffffffffffffffffffffff163314612b33576040517fd238ed5900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6112a881613712565b3b151590565b600080612b50606484614a6d565b60008181526014602052604090205490915073ffffffffffffffffffffffffffffffffffffffff16612b855750600092915050565b6000818152601460205260409020547501000000000000000000000000000000000000000000900463ffffffff16421015612bf257600081815260146020526040902054612be99073ffffffffffffffffffffffffffffffffffffffff1684612c32565b50600192915050565b600090815260146020526040812080547fffffffffffffff0000000000000000000000000000000000000000000000000016905592915050565b50919050565b612c3c82826137de565b601180547fff0000000000000000000000ffffffffffffffffffffffffffffffffffffffff811674010000000000000000000000000000000000000000918290046affffffffffffffffffffff908116600101169091021790556012546040517f25b4e7be0000000000000000000000000000000000000000000000000000000081526004810183905273ffffffffffffffffffffffffffffffffffffffff909116906325b4e7be906024016020604051808303816000875af1158015612d07573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d2b9190614aa8565b6118a6576040517f110e7d7800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6110cb612d6d84611940565b612d7684611940565b600161391f565b60005462010000900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614612e00576040517fd238ed5900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16639bb8dcfd612e7a7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5473ffffffffffffffffffffffffffffffffffffffff1690565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b16815273ffffffffffffffffffffffffffffffffffffffff91821660048201529084166024820152604401602060405180830381865afa158015612eeb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f0f9190614aa8565b6112a8576040517fc40d973400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff821660048201526024015b60405180910390fd5b7f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd91435460ff1615612f95576110cb83613b36565b8273ffffffffffffffffffffffffffffffffffffffff166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa92505050801561301a575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820190925261301791810190614ac5565b60015b613050576040517fc0bb20b200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc81146130a9576040517f0849b49600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b506110cb838383613bec565b6130be81613c17565b50601180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6affffffffffffffffffffff7401000000000000000000000000000000000000000080840482169290920116027fff0000000000000000000000ffffffffffffffffffffffffffffffffffffffff909116179055565b73ffffffffffffffffffffffffffffffffffffffff81166131585750805b600061316383611940565b73ffffffffffffffffffffffffffffffffffffffff8481166000818152600e602052604080822080547fffffffffffffffffffffffff000000000000000000000000000000000000000016888616908117909155905194955093928516927f3134e8a2e6d97e929a7e54011ea5485d7d196dd5f0ba4d4ef95803e8e3fc257f9190a46110cb81836131f386611c22565b61391f565b600054610100900460ff16613239576040517f624bb4ce00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600255565b600054610100900460ff16613281576040517f624bb4ce00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080547fffffffffffffffffffff0000000000000000000000000000000000000000ffff166201000073ffffffffffffffffffffffffffffffffffffffff84169081029190911782556040519091907f8292fce18fa69edf4db7b94ea2e58241df0ae57f97e0a6c9b29067028bf92d76908290a350565b600080805b8381101561364f57600085858381811061331a5761331a61488b565b905060600201602001359050806000036133345750613647565b928301926063841115613373576040517f91cc635e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60ff8316600081815260136020526040902060019094019387878581811061339d5761339d61488b565b6133b392602060609092020190810191506141b0565b81547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff919091161781558787858181106134055761340561488b565b83547fffffffffffffff0000000000ffffffffffffffffffffffffffffffffffffffff167501000000000000000000000000000000000000000000606092909202939093016040013563ffffffff16027fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff16919091177401000000000000000000000000000000000000000060ff861602178255506000836064816134ac576134ac61470d565b0490506000805b85811015613640576134c482613d39565b60008181526014602052604090819020865481547fffffffffffffffffffffffff0000000000000000000000000000000000000000811673ffffffffffffffffffffffffffffffffffffffff9092169182178355885460ff740100000000000000000000000000000000000000009182900416027fffffffffffffffffffffff00000000000000000000000000000000000000000090911690911717808255875463ffffffff75010000000000000000000000000000000000000000009182900416027fffffffffffffff00000000ffffffffffffffffffffffffffffffffffffffffff909116179055519092507fe9af43aba12c8c691c53cf87a0d60c9ff279731244b2186b92c6a90b535a2d2c906136289084908890889092835260208301919091525473ffffffffffffffffffffffffffffffffffffffff8116604083015260a081811c60ff16606084015260a89190911c63ffffffff1660808301520190565b60405180910390a160648284010691506001016134b3565b5050505050505b6001016132fe565b506012805460ff9384167f01000000000000000000000000000000000000000000000000000000000000009081027effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff92831617909255601180549390941690910291161790555050565b600054610100900460ff166136f9576040517f624bb4ce00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60086137058382614b2c565b5060096110cb8282614b2c565b6000805460405173ffffffffffffffffffffffffffffffffffffffff808516936201000090930416917f8292fce18fa69edf4db7b94ea2e58241df0ae57f97e0a6c9b29067028bf92d7691a36000805473ffffffffffffffffffffffffffffffffffffffff80841662010000027fffffffffffffffffffff0000000000000000000000000000000000000000ffff9092169190911790915560015416156112a857600180547fffffffffffffffffffffffff000000000000000000000000000000000000000016905550565b73ffffffffffffffffffffffffffffffffffffffff821661382b576040517f66e7950900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000818152600a602052604090205473ffffffffffffffffffffffffffffffffffffffff1615613887576040517fdfa4c0d500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff82166000818152600b6020908152604080832080546001019055848352600a90915280822080547fffffffffffffffffffffffff0000000000000000000000000000000000000000168417905551839291907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a46118a660008383612d61565b8173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161415801561395b5750600081115b156110cb5773ffffffffffffffffffffffffffffffffffffffff831615613a495773ffffffffffffffffffffffffffffffffffffffff83166000908152600f60205260408120549080808315613a345750505073ffffffffffffffffffffffffffffffffffffffff841660009081526010602090815260408083207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff850180855292529091205468010000000000000000810477ffffffffffffffffffffffffffffffffffffffffffffffff169067ffffffffffffffff165b613a4487858584868a8803613d7b565b505050505b73ffffffffffffffffffffffffffffffffffffffff8216156110cb5773ffffffffffffffffffffffffffffffffffffffff82166000908152600f60205260408120549080808315613b1d5750505073ffffffffffffffffffffffffffffffffffffffff831660009081526010602090815260408083207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff850180855292529091205468010000000000000000810477ffffffffffffffffffffffffffffffffffffffffffffffff169067ffffffffffffffff165b613b2d86858584868a8801613d7b565b50505050505050565b803b613b86576040517fc40d973400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff82166004820152602401612f59565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b613bf583613ee8565b600082511180613c025750805b156110cb57613c118383613f3d565b50505050565b6000818152600a602052604090205473ffffffffffffffffffffffffffffffffffffffff1680613c73576040517f29074bf900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81166000818152600b6020908152604080832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff019055858352600a825280832080547fffffffffffffffffffffffff0000000000000000000000000000000000000000908116909155600c9092528083208054909216909155518492907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908390a46118a681600084612d61565b60005b60008281526014602052604090205473ffffffffffffffffffffffffffffffffffffffff1615613d7757600190910190606482069150613d3c565b5090565b600085118015613d8a57504283145b15613df95773ffffffffffffffffffffffffffffffffffffffff861660009081526010602090815260408083208784529091529020805467ffffffffffffffff166801000000000000000077ffffffffffffffffffffffffffffffffffffffffffffffff841602179055613e8f565b73ffffffffffffffffffffffffffffffffffffffff8616600081815260106020908152604080832089845282528083204267ffffffffffffffff1677ffffffffffffffffffffffffffffffffffffffffffffffff871668010000000000000000027fffffffffffffffffffffffffffffffffffffffffffffffff000000000000000016179055928252600f905220805460010190555b604080518381526020810183905273ffffffffffffffffffffffffffffffffffffffff8816917fdec2bacdd2f05b59de34da9b523dff8be42e5e38e818c82fdb0bae774387a724910160405180910390a2505050505050565b613ef181613b36565b60405173ffffffffffffffffffffffffffffffffffffffff821681527fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b9060200160405180910390a150565b6060823b613f77576040517f37f2022900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000808473ffffffffffffffffffffffffffffffffffffffff1684604051613f9f9190614c46565b600060405180830381855af49150503d8060008114613fda576040519150601f19603f3d011682016040523d82523d6000602084013e613fdf565b606091505b5091509150613fee8282613ff7565b95945050505050565b60608215614006575080610af2565b8151156140165781518083602001fd5b6040517f62536b1000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7fffffffff00000000000000000000000000000000000000000000000000000000811681146112a857600080fd5b60006020828403121561408857600080fd5b813561197881614048565b60005b838110156140ae578181015183820152602001614096565b50506000910152565b60208152600082518060208401526140d6816040850160208701614093565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169190910160400192915050565b60006020828403121561411a57600080fd5b5035919050565b73ffffffffffffffffffffffffffffffffffffffff811681146112a857600080fd5b6000806040838503121561415657600080fd5b823561416181614121565b946020939093013593505050565b60008060006060848603121561418457600080fd5b833561418f81614121565b9250602084013561419f81614121565b929592945050506040919091013590565b6000602082840312156141c257600080fd5b813561197881614121565b815173ffffffffffffffffffffffffffffffffffffffff16815260208083015160ff169082015260408083015163ffffffff169082015260608101610af2565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff811182821017156142835761428361420d565b604052919050565b600067ffffffffffffffff8211156142a5576142a561420d565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b60006142e46142df8461428b565b61423c565b90508281528383830111156142f857600080fd5b828260208301376000602084830101529392505050565b6000806040838503121561432257600080fd5b823561432d81614121565b9150602083013567ffffffffffffffff81111561434957600080fd5b8301601f8101851361435a57600080fd5b614369858235602084016142d1565b9150509250929050565b60008083601f84011261438557600080fd5b50813567ffffffffffffffff81111561439d57600080fd5b6020830191508360206060830285010111156143b857600080fd5b9250929050565b60008083601f8401126143d157600080fd5b50813567ffffffffffffffff8111156143e957600080fd5b6020830191508360208285010111156143b857600080fd5b600080600080600080600060a0888a03121561441c57600080fd5b873567ffffffffffffffff8082111561443457600080fd5b6144408b838c01614373565b909950975060208a013591508082111561445957600080fd5b506144668a828b016143bf565b909650945050604088013561447a81614121565b9250606088013561448a81614121565b9150608088013561449a81614121565b8091505092959891949750929550565b80151581146112a857600080fd5b600080604083850312156144cb57600080fd5b82356144d681614121565b915060208301356144e6816144aa565b809150509250929050565b60008060008060008060c0878903121561450a57600080fd5b863561451581614121565b9550602087013561452581614121565b945060408701359350606087013560ff8116811461454257600080fd5b9598949750929560808101359460a0909101359350915050565b6020808252825182820181905260009190848201906040850190845b818110156145d1576145be838551805173ffffffffffffffffffffffffffffffffffffffff16825260208082015160ff169083015260409081015163ffffffff16910152565b9284019260609290920191600101614578565b50909695505050505050565b6000806000806000608086880312156145f557600080fd5b853561460081614121565b9450602086013561461081614121565b935060408601359250606086013567ffffffffffffffff81111561463357600080fd5b61463f888289016143bf565b969995985093965092949392505050565b6000806020838503121561466357600080fd5b823567ffffffffffffffff81111561467a57600080fd5b61468685828601614373565b90969095509350505050565b600080604083850312156146a557600080fd5b82356146b081614121565b915060208301356144e681614121565b600181811c908216806146d457607f821691505b602082108103612c2c577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b60006020828403121561474e57600080fd5b815161197881614048565b600082601f83011261476a57600080fd5b611978838335602085016142d1565b60008060008060008060c0878903121561479257600080fd5b863567ffffffffffffffff808211156147aa57600080fd5b6147b68a838b01614759565b975060208901359150808211156147cc57600080fd5b6147d88a838b01614759565b965060408901359150808211156147ee57600080fd5b6147fa8a838b01614759565b9550606089013591508082111561481057600080fd5b61481c8a838b01614759565b9450608089013591508082111561483257600080fd5b61483e8a838b01614759565b935060a089013591508082111561485457600080fd5b5061486189828a01614759565b9150509295509295509295565b60006020828403121561488057600080fd5b815161197881614121565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600073ffffffffffffffffffffffffffffffffffffffff808816835280871660208401525084604083015260806060830152826080830152828460a0840137600060a0848401015260a07fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f85011683010190509695505050505050565b60006020828403121561494b57600080fd5b815167ffffffffffffffff81111561496257600080fd5b8201601f8101841361497357600080fd5b80516149816142df8261428b565b81815285602083850101111561499657600080fd5b613fee826020830160208601614093565b8381526020810183905260a081016149f56040830184805173ffffffffffffffffffffffffffffffffffffffff16825260208082015160ff169083015260409081015163ffffffff16910152565b949350505050565b6020808252818101839052600090604080840186845b87811015614a60578135614a2681614121565b73ffffffffffffffffffffffffffffffffffffffff1683528185013585840152838201358484015260609283019290910190600101614a13565b5090979650505050505050565b600082614aa3577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500690565b600060208284031215614aba57600080fd5b8151611978816144aa565b600060208284031215614ad757600080fd5b5051919050565b601f8211156110cb57600081815260208120601f850160051c81016020861015614b055750805b601f850160051c820191505b81811015614b2457828155600101614b11565b505050505050565b815167ffffffffffffffff811115614b4657614b4661420d565b614b5a81614b5484546146c0565b84614ade565b602080601f831160018114614bad5760008415614b775750858301515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600386901b1c1916600185901b178555614b24565b6000858152602081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08616915b82811015614bfa57888601518255948401946001909101908401614bdb565b5085821015614c3657878501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600388901b60f8161c191681555b5050505050600190811b01905550565b60008251614c58818460208701614093565b919091019291505056fea26469706673582212200bfb0be60a592c669e79d483768719bea2aa6f04d756a989444646671fbb8a8564736f6c63430008100033000000000000000000000000d310a3041dfcf14def5ccbc508668974b5da7174
Deployed Bytecode
0x6080604052600436106102e75760003560e01c806370a0823111610184578063b20d7fa9116100d6578063d9d3e0901161008a578063e8a3d48511610064578063e8a3d48514610988578063e985e9c51461099d578063f2fde38b146109f357600080fd5b8063d9d3e09014610902578063dc276e571461093d578063e30c39781461095d57600080fd5b8063b88d4fde116100bb578063b88d4fde146108a2578063c87b56dd146108c2578063d1bfda66146108e257600080fd5b8063b20d7fa914610860578063b73cdd191461088057600080fd5b80638da5cb5b116101385780639d8aefc2116101125780639d8aefc2146107e5578063a0a8e460146107fa578063a22cb4651461084057600080fd5b80638da5cb5b1461077f57806395d89b41146107b05780639ab24eb0146107c557600080fd5b806374fd46551161016957806374fd46551461070457806379ba50971461073f5780637d9f6db51461075457600080fd5b806370a08231146106a157806370ae92d2146106c157600080fd5b80633a46b1a81161023d57806352d1902d116101f15780636097bf62116101cb5780636097bf62146106365780636352211e14610656578063703199701461067657600080fd5b806352d1902d146105e1578063587cde1e146105f65780635c19a95c1461061657600080fd5b806342842e0e1161022257806342842e0e1461058e57806342966c68146105ae5780634f1ef286146105ce57600080fd5b80633a46b1a8146104b45780633bcb43f3146104d457600080fd5b806318160ddd1161029f5780633644e515116102795780633644e5151461045f5780633659cfe614610474578063395db2cd1461049457600080fd5b806318160ddd146103f057806323452b9c1461042a57806323b872dd1461043f57600080fd5b8063081812fc116102d0578063081812fc14610343578063095ea7b3146103ab5780631249c58b146103cd57600080fd5b806301ffc9a7146102ec57806306fdde0314610321575b600080fd5b3480156102f857600080fd5b5061030c610307366004614076565b610a13565b60405190151581526020015b60405180910390f35b34801561032d57600080fd5b50610336610af8565b60405161031891906140b7565b34801561034f57600080fd5b5061038661035e366004614108565b6000908152600c602052604090205473ffffffffffffffffffffffffffffffffffffffff1690565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610318565b3480156103b757600080fd5b506103cb6103c6366004614143565b610b86565b005b3480156103d957600080fd5b506103e2610ca4565b604051908152602001610318565b3480156103fc57600080fd5b506011547401000000000000000000000000000000000000000090046affffffffffffffffffffff166103e2565b34801561043657600080fd5b506103cb610db6565b34801561044b57600080fd5b506103cb61045a36600461416f565b610e88565b34801561046b57600080fd5b506103e26110d0565b34801561048057600080fd5b506103cb61048f3660046141b0565b611153565b3480156104a057600080fd5b506103cb6104af3660046141b0565b6112ab565b3480156104c057600080fd5b506103e26104cf366004614143565b61137f565b3480156104e057600080fd5b506105816104ef366004614108565b6040805160608082018352600080835260208084018290529284018190529384526013825292829020825193840183525473ffffffffffffffffffffffffffffffffffffffff8116845274010000000000000000000000000000000000000000810460ff16918401919091527501000000000000000000000000000000000000000000900463ffffffff169082015290565b60405161031891906141cd565b34801561059a57600080fd5b506103cb6105a936600461416f565b6115e3565b3480156105ba57600080fd5b506103cb6105c9366004614108565b611706565b6103cb6105dc36600461430f565b611760565b3480156105ed57600080fd5b506103e26118aa565b34801561060257600080fd5b506103866106113660046141b0565b611940565b34801561062257600080fd5b506103cb6106313660046141b0565b61197f565b34801561064257600080fd5b506103cb610651366004614401565b611989565b34801561066257600080fd5b50610386610671366004614108565b611bc6565b34801561068257600080fd5b5060125473ffffffffffffffffffffffffffffffffffffffff16610386565b3480156106ad57600080fd5b506103e26106bc3660046141b0565b611c22565b3480156106cd57600080fd5b506103e26106dc3660046141b0565b73ffffffffffffffffffffffffffffffffffffffff1660009081526007602052604090205490565b34801561071057600080fd5b506011547f0100000000000000000000000000000000000000000000000000000000000000900460ff166103e2565b34801561074b57600080fd5b506103cb611c9a565b34801561076057600080fd5b5060115473ffffffffffffffffffffffffffffffffffffffff16610386565b34801561078b57600080fd5b5060005462010000900473ffffffffffffffffffffffffffffffffffffffff16610386565b3480156107bc57600080fd5b50610336611da4565b3480156107d157600080fd5b506103e26107e03660046141b0565b611db1565b3480156107f157600080fd5b506103cb611e80565b34801561080657600080fd5b5060408051808201909152600581527f312e312e300000000000000000000000000000000000000000000000000000006020820152610336565b34801561084c57600080fd5b506103cb61085b3660046144b8565b611f6f565b34801561086c57600080fd5b506103cb61087b3660046144f1565b612006565b34801561088c57600080fd5b5061089561225b565b604051610318919061455c565b3480156108ae57600080fd5b506103cb6108bd3660046145dd565b6123c5565b3480156108ce57600080fd5b506103366108dd366004614108565b6124dd565b3480156108ee57600080fd5b506103cb6108fd366004614650565b612593565b34801561090e57600080fd5b506012547f0100000000000000000000000000000000000000000000000000000000000000900460ff166103e2565b34801561094957600080fd5b50610581610958366004614108565b612978565b34801561096957600080fd5b5060015473ffffffffffffffffffffffffffffffffffffffff16610386565b34801561099457600080fd5b50610336612a26565b3480156109a957600080fd5b5061030c6109b8366004614692565b73ffffffffffffffffffffffffffffffffffffffff9182166000908152600d6020908152604080832093909416825291909152205460ff1690565b3480156109ff57600080fd5b506103cb610a0e3660046141b0565b612adc565b60007f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff0000000000000000000000000000000000000000000000000000000083161480610aa657507f80ac58cd000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316145b80610af257507f5b5e139f000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316145b92915050565b60088054610b05906146c0565b80601f0160208091040260200160405190810160405280929190818152602001828054610b31906146c0565b8015610b7e5780601f10610b5357610100808354040283529160200191610b7e565b820191906000526020600020905b815481529060010190602001808311610b6157829003601f168201915b505050505081565b6000818152600a602052604090205473ffffffffffffffffffffffffffffffffffffffff16338114801590610bec575073ffffffffffffffffffffffffffffffffffffffff81166000908152600d6020908152604080832033845290915290205460ff16155b15610c23576040517f3201fe7300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000828152600c602052604080822080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff87811691821790925591518593918516917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591a4505050565b60006002805403610ce1576040517fad2ce74900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6002805560115473ffffffffffffffffffffffffffffffffffffffff16338114610d37576040517f3b30aafa00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b601280547fff0000000000000000000000ffffffffffffffffffffffffffffffffffffffff8116600174010000000000000000000000000000000000000000928390046affffffffffffffffffffff90811691820116909202179091559150610d9f82612b42565b610d3757610dad8183612c32565b50600160025590565b60005462010000900473ffffffffffffffffffffffffffffffffffffffff163314610e0d576040517fd238ed5900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001546000805460405173ffffffffffffffffffffffffffffffffffffffff9384169362010000909204909116917f682679deecef4dcd49674845cc1e3a075fea9073680aa445a8207d5a4bdea3da91a3600180547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055565b6000818152600a602052604090205473ffffffffffffffffffffffffffffffffffffffff848116911614610ee8576040517f9d2d273100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8216610f35576040517f66e7950900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3373ffffffffffffffffffffffffffffffffffffffff841614801590610f8c575073ffffffffffffffffffffffffffffffffffffffff83166000908152600d6020908152604080832033845290915290205460ff16155b8015610fbc57506000818152600c602052604090205473ffffffffffffffffffffffffffffffffffffffff163314155b15610ff3576040517f3201fe7300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8084166000818152600b6020908152604080832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01905593861680835284832080546001019055858352600a825284832080547fffffffffffffffffffffffff00000000000000000000000000000000000000009081168317909155600c90925284832080549092169091559251849392917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a46110cb838383612d61565b505050565b6000600654461461114c57611147600354600454604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60208201529081019290925260608201524660808201523060a082015260009060c00160405160208183030381529060405280519060200120905090565b905090565b5060055490565b73ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000e6322201ced0a4d6595968411285a39ccf9d59891630036111c2576040517f43d22ee900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000e6322201ced0a4d6595968411285a39ccf9d598973ffffffffffffffffffffffffffffffffffffffff166112377f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff1614611284576040517fe74d90a000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61128d81612d7d565b6112a881604051806020016040528060008152506000612f62565b50565b60005462010000900473ffffffffffffffffffffffffffffffffffffffff163314611302576040517fd238ed5900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff8381169182179092556000805460405192936201000090910416917f4f2638f5949b9614ef8d5e268cb51348ad7f434a34812bf64b6e95014fbd357e9190a350565b60004282106113ba576040517f118818d100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff83166000908152600f6020526040812054908190036113f2576000915050610af2565b73ffffffffffffffffffffffffffffffffffffffff841660009081526010602090815260408083207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff85018085529281905292205467ffffffffffffffff168510611496576000908152602091909152604090205468010000000000000000900477ffffffffffffffffffffffffffffffffffffffffffffffff169150610af29050565b60008080526020839052604090205467ffffffffffffffff168510156114c25760009350505050610af2565b60408051808201909152600080825260208201819052829181905b828411156115a05760028385030484036000818152602088815260409182902082518084019093525467ffffffffffffffff81168084526801000000000000000090910477ffffffffffffffffffffffffffffffffffffffffffffffff1691830191909152919350915089900361157a576020015177ffffffffffffffffffffffffffffffffffffffffffffffff169650610af295505050505050565b805167ffffffffffffffff16891115611595578192506114dd565b6001820393506114dd565b505060009081526020939093525050604090205468010000000000000000900477ffffffffffffffffffffffffffffffffffffffffffffffff1691505092915050565b6115ee838383610e88565b813b151580156116cf57506040517f150b7a020000000000000000000000000000000000000000000000000000000080825233600483015273ffffffffffffffffffffffffffffffffffffffff858116602484015260448301849052608060648401526000608484015290919084169063150b7a029060a4016020604051808303816000875af1158015611686573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116aa919061473c565b7fffffffff000000000000000000000000000000000000000000000000000000001614155b156110cb576040517f521005a600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60115473ffffffffffffffffffffffffffffffffffffffff163314611757576040517f3b30aafa00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6112a8816130b5565b73ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000e6322201ced0a4d6595968411285a39ccf9d59891630036117cf576040517f43d22ee900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000e6322201ced0a4d6595968411285a39ccf9d598973ffffffffffffffffffffffffffffffffffffffff166118447f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff1614611891576040517fe74d90a000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61189a82612d7d565b6118a682826001612f62565b5050565b60003073ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000e6322201ced0a4d6595968411285a39ccf9d5989161461191b576040517f575bc92e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b507f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc90565b73ffffffffffffffffffffffffffffffffffffffff8082166000908152600e602052604081205490911680156119765780611978565b825b9392505050565b6112a8338261313a565b600054610100900460ff16158015806119a6575060005460ff1615155b80156119c25750303b1515806119c2575060005460ff16600114155b156119f9576040517f439a74c900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790558015611a5757600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b3373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000d310a3041dfcf14def5ccbc508668974b5da71741614611ac6576040517fa2ddd97100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611ace6131f8565b611ad782613240565b611ae188886132f9565b600080611af087890189614779565b5050505091509150611b0282826136b8565b50506012805473ffffffffffffffffffffffffffffffffffffffff8087167fffffffffffffffffffffffff00000000000000000000000000000000000000009283161790925560118054928616929091169190911790558015611bbc57600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527fbe9b076dc5b65990cca9dd9d7366682482e7817a6f6bc7f4faf4dc32af497f329060200160405180910390a15b5050505050505050565b6000818152600a602052604081205473ffffffffffffffffffffffffffffffffffffffff1680610af2576040517f9d2d273100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff8216611c71576040517f66e7950900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5073ffffffffffffffffffffffffffffffffffffffff166000908152600b602052604090205490565b60015473ffffffffffffffffffffffffffffffffffffffff163314611ceb576040517f065cd53100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000805460405133926201000090920473ffffffffffffffffffffffffffffffffffffffff16917f8292fce18fa69edf4db7b94ea2e58241df0ae57f97e0a6c9b29067028bf92d7691a360018054600080547fffffffffffffffffffff0000000000000000000000000000000000000000ffff1673ffffffffffffffffffffffffffffffffffffffff831662010000021790557fffffffffffffffffffffffff0000000000000000000000000000000000000000169055565b60098054610b05906146c0565b73ffffffffffffffffffffffffffffffffffffffff81166000908152600f6020526040812054808203611de5576000611e5f565b73ffffffffffffffffffffffffffffffffffffffff831660009081526010602090815260408083207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8501845290915290205468010000000000000000900477ffffffffffffffffffffffffffffffffffffffffffffffff165b77ffffffffffffffffffffffffffffffffffffffffffffffff169392505050565b60115473ffffffffffffffffffffffffffffffffffffffff163314611ed1576040517f3b30aafa00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b601154604080517f61d027b30000000000000000000000000000000000000000000000000000000081529051611f6d9273ffffffffffffffffffffffffffffffffffffffff16916361d027b391600480830192602092919082900301816000875af1158015611f44573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f68919061486e565b613712565b565b336000818152600d6020908152604080832073ffffffffffffffffffffffffffffffffffffffff87168085529083529281902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001686151590811790915590519081529192917f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a35050565b83421115612040576040517f6ed6bef000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600061204a6110d0565b73ffffffffffffffffffffffffffffffffffffffff88811660008181526007602090815260409182902080546001810190915582517f9ba0adc65ac9b85f9640562bd298ef1e78f86fbfbc6433772a69f08b092c5b238184015280840194909452938b166060840152608083019390935260a08083018a90528151808403909101815260c0830190915280519201919091207f190100000000000000000000000000000000000000000000000000000000000060e083015260e282019290925261010281019190915261012201604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181528282528051602091820120600080855291840180845281905260ff88169284019290925260608301869052608083018590529092509060019060a0016020604051602081039080840390855afa1580156121a0573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015191505073ffffffffffffffffffffffffffffffffffffffff8116158061221a57508773ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614155b15612251576040517fa3402a3800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611bbc888861313a565b6011546060907f0100000000000000000000000000000000000000000000000000000000000000900460ff1660008167ffffffffffffffff8111156122a2576122a261420d565b60405190808252806020026020018201604052801561230b57816020015b60408051606081018252600080825260208083018290529282015282527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9092019101816122c05790505b50905060005b828110156123be576000818152601360209081526040918290208251606081018452905473ffffffffffffffffffffffffffffffffffffffff8116825274010000000000000000000000000000000000000000810460ff1692820192909252750100000000000000000000000000000000000000000090910463ffffffff169181019190915282518390839081106123ab576123ab61488b565b6020908102919091010152600101612311565b5092915050565b6123d0858585610e88565b833b1515801561249f57506040517f150b7a02000000000000000000000000000000000000000000000000000000008082529073ffffffffffffffffffffffffffffffffffffffff86169063150b7a02906124379033908a908990899089906004016148ba565b6020604051808303816000875af1158015612456573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061247a919061473c565b7fffffffff000000000000000000000000000000000000000000000000000000001614155b156124d6576040517f521005a600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5050505050565b6012546040517fc87b56dd0000000000000000000000000000000000000000000000000000000081526004810183905260609173ffffffffffffffffffffffffffffffffffffffff169063c87b56dd90602401600060405180830381865afa15801561254d573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052610af29190810190614939565b60005462010000900473ffffffffffffffffffffffffffffffffffffffff1633146125ea576040517fd238ed5900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6011547f0100000000000000000000000000000000000000000000000000000000000000900460ff1660008167ffffffffffffffff81111561262e5761262e61420d565b60405190808252806020026020018201604052801561269757816020015b60408051606081018252600080825260208083018290529282015282527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90920191018161264c5790505b50905060005b8281101561274a576000818152601360209081526040918290208251606081018452905473ffffffffffffffffffffffffffffffffffffffff8116825274010000000000000000000000000000000000000000810460ff1692820192909252750100000000000000000000000000000000000000000090910463ffffffff169181019190915282518390839081106127375761273761488b565b602090810291909101015260010161269d565b50604080516064808252610ca0820190925260009160208201610c808036833701905050905060005b82518110156129005760008382815181106127905761279061488b565b6020908102919091018101516000848152601383526040812080547fffffffffffffff000000000000000000000000000000000000000000000000001690559181015190925060ff1690036127e557506128f8565b6000816020015160ff166064816127fe576127fe61470d565b0460ff1690506000805b836020015160ff168110156128f3575b85828151811061282a5761282a61488b565b60209081029190910101511561284b57600190910190606482069150612818565b600082815260146020526040902080547fffffffffffffff0000000000000000000000000000000000000000000000000016905585516001908790849081106128965761289661488b565b6020026020010190151590811515815250507f6309c4a2f8a0b726702416b909c21dce80f888bf255698775cd12336acd16b958286866040516128db939291906149a7565b60405180910390a16064828401069150600101612808565b505050505b600101612773565b50601180547effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9081169091556012805490911690556040517f6fb4c002bf55855ac8dd687342fe82b08a0a20ea80a7588566bfc6703bae213f9061296690879087906149fd565b60405180910390a16124d685856132f9565b6040805160608101825260008082526020820181905291810191909152601460006129a4606485614a6d565b815260208082019290925260409081016000208151606081018352905473ffffffffffffffffffffffffffffffffffffffff8116825274010000000000000000000000000000000000000000810460ff1693820193909352750100000000000000000000000000000000000000000090920463ffffffff169082015292915050565b601254604080517fe8a3d485000000000000000000000000000000000000000000000000000000008152905160609273ffffffffffffffffffffffffffffffffffffffff169163e8a3d4859160048083019260009291908290030181865afa158015612a96573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526111479190810190614939565b60005462010000900473ffffffffffffffffffffffffffffffffffffffff163314612b33576040517fd238ed5900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6112a881613712565b3b151590565b600080612b50606484614a6d565b60008181526014602052604090205490915073ffffffffffffffffffffffffffffffffffffffff16612b855750600092915050565b6000818152601460205260409020547501000000000000000000000000000000000000000000900463ffffffff16421015612bf257600081815260146020526040902054612be99073ffffffffffffffffffffffffffffffffffffffff1684612c32565b50600192915050565b600090815260146020526040812080547fffffffffffffff0000000000000000000000000000000000000000000000000016905592915050565b50919050565b612c3c82826137de565b601180547fff0000000000000000000000ffffffffffffffffffffffffffffffffffffffff811674010000000000000000000000000000000000000000918290046affffffffffffffffffffff908116600101169091021790556012546040517f25b4e7be0000000000000000000000000000000000000000000000000000000081526004810183905273ffffffffffffffffffffffffffffffffffffffff909116906325b4e7be906024016020604051808303816000875af1158015612d07573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d2b9190614aa8565b6118a6576040517f110e7d7800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6110cb612d6d84611940565b612d7684611940565b600161391f565b60005462010000900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614612e00576040517fd238ed5900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000d310a3041dfcf14def5ccbc508668974b5da717473ffffffffffffffffffffffffffffffffffffffff16639bb8dcfd612e7a7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5473ffffffffffffffffffffffffffffffffffffffff1690565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b16815273ffffffffffffffffffffffffffffffffffffffff91821660048201529084166024820152604401602060405180830381865afa158015612eeb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f0f9190614aa8565b6112a8576040517fc40d973400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff821660048201526024015b60405180910390fd5b7f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd91435460ff1615612f95576110cb83613b36565b8273ffffffffffffffffffffffffffffffffffffffff166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa92505050801561301a575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820190925261301791810190614ac5565b60015b613050576040517fc0bb20b200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc81146130a9576040517f0849b49600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b506110cb838383613bec565b6130be81613c17565b50601180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6affffffffffffffffffffff7401000000000000000000000000000000000000000080840482169290920116027fff0000000000000000000000ffffffffffffffffffffffffffffffffffffffff909116179055565b73ffffffffffffffffffffffffffffffffffffffff81166131585750805b600061316383611940565b73ffffffffffffffffffffffffffffffffffffffff8481166000818152600e602052604080822080547fffffffffffffffffffffffff000000000000000000000000000000000000000016888616908117909155905194955093928516927f3134e8a2e6d97e929a7e54011ea5485d7d196dd5f0ba4d4ef95803e8e3fc257f9190a46110cb81836131f386611c22565b61391f565b600054610100900460ff16613239576040517f624bb4ce00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600255565b600054610100900460ff16613281576040517f624bb4ce00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080547fffffffffffffffffffff0000000000000000000000000000000000000000ffff166201000073ffffffffffffffffffffffffffffffffffffffff84169081029190911782556040519091907f8292fce18fa69edf4db7b94ea2e58241df0ae57f97e0a6c9b29067028bf92d76908290a350565b600080805b8381101561364f57600085858381811061331a5761331a61488b565b905060600201602001359050806000036133345750613647565b928301926063841115613373576040517f91cc635e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60ff8316600081815260136020526040902060019094019387878581811061339d5761339d61488b565b6133b392602060609092020190810191506141b0565b81547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff919091161781558787858181106134055761340561488b565b83547fffffffffffffff0000000000ffffffffffffffffffffffffffffffffffffffff167501000000000000000000000000000000000000000000606092909202939093016040013563ffffffff16027fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff16919091177401000000000000000000000000000000000000000060ff861602178255506000836064816134ac576134ac61470d565b0490506000805b85811015613640576134c482613d39565b60008181526014602052604090819020865481547fffffffffffffffffffffffff0000000000000000000000000000000000000000811673ffffffffffffffffffffffffffffffffffffffff9092169182178355885460ff740100000000000000000000000000000000000000009182900416027fffffffffffffffffffffff00000000000000000000000000000000000000000090911690911717808255875463ffffffff75010000000000000000000000000000000000000000009182900416027fffffffffffffff00000000ffffffffffffffffffffffffffffffffffffffffff909116179055519092507fe9af43aba12c8c691c53cf87a0d60c9ff279731244b2186b92c6a90b535a2d2c906136289084908890889092835260208301919091525473ffffffffffffffffffffffffffffffffffffffff8116604083015260a081811c60ff16606084015260a89190911c63ffffffff1660808301520190565b60405180910390a160648284010691506001016134b3565b5050505050505b6001016132fe565b506012805460ff9384167f01000000000000000000000000000000000000000000000000000000000000009081027effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff92831617909255601180549390941690910291161790555050565b600054610100900460ff166136f9576040517f624bb4ce00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60086137058382614b2c565b5060096110cb8282614b2c565b6000805460405173ffffffffffffffffffffffffffffffffffffffff808516936201000090930416917f8292fce18fa69edf4db7b94ea2e58241df0ae57f97e0a6c9b29067028bf92d7691a36000805473ffffffffffffffffffffffffffffffffffffffff80841662010000027fffffffffffffffffffff0000000000000000000000000000000000000000ffff9092169190911790915560015416156112a857600180547fffffffffffffffffffffffff000000000000000000000000000000000000000016905550565b73ffffffffffffffffffffffffffffffffffffffff821661382b576040517f66e7950900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000818152600a602052604090205473ffffffffffffffffffffffffffffffffffffffff1615613887576040517fdfa4c0d500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff82166000818152600b6020908152604080832080546001019055848352600a90915280822080547fffffffffffffffffffffffff0000000000000000000000000000000000000000168417905551839291907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a46118a660008383612d61565b8173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161415801561395b5750600081115b156110cb5773ffffffffffffffffffffffffffffffffffffffff831615613a495773ffffffffffffffffffffffffffffffffffffffff83166000908152600f60205260408120549080808315613a345750505073ffffffffffffffffffffffffffffffffffffffff841660009081526010602090815260408083207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff850180855292529091205468010000000000000000810477ffffffffffffffffffffffffffffffffffffffffffffffff169067ffffffffffffffff165b613a4487858584868a8803613d7b565b505050505b73ffffffffffffffffffffffffffffffffffffffff8216156110cb5773ffffffffffffffffffffffffffffffffffffffff82166000908152600f60205260408120549080808315613b1d5750505073ffffffffffffffffffffffffffffffffffffffff831660009081526010602090815260408083207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff850180855292529091205468010000000000000000810477ffffffffffffffffffffffffffffffffffffffffffffffff169067ffffffffffffffff165b613b2d86858584868a8801613d7b565b50505050505050565b803b613b86576040517fc40d973400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff82166004820152602401612f59565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b613bf583613ee8565b600082511180613c025750805b156110cb57613c118383613f3d565b50505050565b6000818152600a602052604090205473ffffffffffffffffffffffffffffffffffffffff1680613c73576040517f29074bf900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81166000818152600b6020908152604080832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff019055858352600a825280832080547fffffffffffffffffffffffff0000000000000000000000000000000000000000908116909155600c9092528083208054909216909155518492907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908390a46118a681600084612d61565b60005b60008281526014602052604090205473ffffffffffffffffffffffffffffffffffffffff1615613d7757600190910190606482069150613d3c565b5090565b600085118015613d8a57504283145b15613df95773ffffffffffffffffffffffffffffffffffffffff861660009081526010602090815260408083208784529091529020805467ffffffffffffffff166801000000000000000077ffffffffffffffffffffffffffffffffffffffffffffffff841602179055613e8f565b73ffffffffffffffffffffffffffffffffffffffff8616600081815260106020908152604080832089845282528083204267ffffffffffffffff1677ffffffffffffffffffffffffffffffffffffffffffffffff871668010000000000000000027fffffffffffffffffffffffffffffffffffffffffffffffff000000000000000016179055928252600f905220805460010190555b604080518381526020810183905273ffffffffffffffffffffffffffffffffffffffff8816917fdec2bacdd2f05b59de34da9b523dff8be42e5e38e818c82fdb0bae774387a724910160405180910390a2505050505050565b613ef181613b36565b60405173ffffffffffffffffffffffffffffffffffffffff821681527fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b9060200160405180910390a150565b6060823b613f77576040517f37f2022900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000808473ffffffffffffffffffffffffffffffffffffffff1684604051613f9f9190614c46565b600060405180830381855af49150503d8060008114613fda576040519150601f19603f3d011682016040523d82523d6000602084013e613fdf565b606091505b5091509150613fee8282613ff7565b95945050505050565b60608215614006575080610af2565b8151156140165781518083602001fd5b6040517f62536b1000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7fffffffff00000000000000000000000000000000000000000000000000000000811681146112a857600080fd5b60006020828403121561408857600080fd5b813561197881614048565b60005b838110156140ae578181015183820152602001614096565b50506000910152565b60208152600082518060208401526140d6816040850160208701614093565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169190910160400192915050565b60006020828403121561411a57600080fd5b5035919050565b73ffffffffffffffffffffffffffffffffffffffff811681146112a857600080fd5b6000806040838503121561415657600080fd5b823561416181614121565b946020939093013593505050565b60008060006060848603121561418457600080fd5b833561418f81614121565b9250602084013561419f81614121565b929592945050506040919091013590565b6000602082840312156141c257600080fd5b813561197881614121565b815173ffffffffffffffffffffffffffffffffffffffff16815260208083015160ff169082015260408083015163ffffffff169082015260608101610af2565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff811182821017156142835761428361420d565b604052919050565b600067ffffffffffffffff8211156142a5576142a561420d565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b60006142e46142df8461428b565b61423c565b90508281528383830111156142f857600080fd5b828260208301376000602084830101529392505050565b6000806040838503121561432257600080fd5b823561432d81614121565b9150602083013567ffffffffffffffff81111561434957600080fd5b8301601f8101851361435a57600080fd5b614369858235602084016142d1565b9150509250929050565b60008083601f84011261438557600080fd5b50813567ffffffffffffffff81111561439d57600080fd5b6020830191508360206060830285010111156143b857600080fd5b9250929050565b60008083601f8401126143d157600080fd5b50813567ffffffffffffffff8111156143e957600080fd5b6020830191508360208285010111156143b857600080fd5b600080600080600080600060a0888a03121561441c57600080fd5b873567ffffffffffffffff8082111561443457600080fd5b6144408b838c01614373565b909950975060208a013591508082111561445957600080fd5b506144668a828b016143bf565b909650945050604088013561447a81614121565b9250606088013561448a81614121565b9150608088013561449a81614121565b8091505092959891949750929550565b80151581146112a857600080fd5b600080604083850312156144cb57600080fd5b82356144d681614121565b915060208301356144e6816144aa565b809150509250929050565b60008060008060008060c0878903121561450a57600080fd5b863561451581614121565b9550602087013561452581614121565b945060408701359350606087013560ff8116811461454257600080fd5b9598949750929560808101359460a0909101359350915050565b6020808252825182820181905260009190848201906040850190845b818110156145d1576145be838551805173ffffffffffffffffffffffffffffffffffffffff16825260208082015160ff169083015260409081015163ffffffff16910152565b9284019260609290920191600101614578565b50909695505050505050565b6000806000806000608086880312156145f557600080fd5b853561460081614121565b9450602086013561461081614121565b935060408601359250606086013567ffffffffffffffff81111561463357600080fd5b61463f888289016143bf565b969995985093965092949392505050565b6000806020838503121561466357600080fd5b823567ffffffffffffffff81111561467a57600080fd5b61468685828601614373565b90969095509350505050565b600080604083850312156146a557600080fd5b82356146b081614121565b915060208301356144e681614121565b600181811c908216806146d457607f821691505b602082108103612c2c577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b60006020828403121561474e57600080fd5b815161197881614048565b600082601f83011261476a57600080fd5b611978838335602085016142d1565b60008060008060008060c0878903121561479257600080fd5b863567ffffffffffffffff808211156147aa57600080fd5b6147b68a838b01614759565b975060208901359150808211156147cc57600080fd5b6147d88a838b01614759565b965060408901359150808211156147ee57600080fd5b6147fa8a838b01614759565b9550606089013591508082111561481057600080fd5b61481c8a838b01614759565b9450608089013591508082111561483257600080fd5b61483e8a838b01614759565b935060a089013591508082111561485457600080fd5b5061486189828a01614759565b9150509295509295509295565b60006020828403121561488057600080fd5b815161197881614121565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600073ffffffffffffffffffffffffffffffffffffffff808816835280871660208401525084604083015260806060830152826080830152828460a0840137600060a0848401015260a07fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f85011683010190509695505050505050565b60006020828403121561494b57600080fd5b815167ffffffffffffffff81111561496257600080fd5b8201601f8101841361497357600080fd5b80516149816142df8261428b565b81815285602083850101111561499657600080fd5b613fee826020830160208601614093565b8381526020810183905260a081016149f56040830184805173ffffffffffffffffffffffffffffffffffffffff16825260208082015160ff169083015260409081015163ffffffff16910152565b949350505050565b6020808252818101839052600090604080840186845b87811015614a60578135614a2681614121565b73ffffffffffffffffffffffffffffffffffffffff1683528185013585840152838201358484015260609283019290910190600101614a13565b5090979650505050505050565b600082614aa3577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500690565b600060208284031215614aba57600080fd5b8151611978816144aa565b600060208284031215614ad757600080fd5b5051919050565b601f8211156110cb57600081815260208120601f850160051c81016020861015614b055750805b601f850160051c820191505b81811015614b2457828155600101614b11565b505050505050565b815167ffffffffffffffff811115614b4657614b4661420d565b614b5a81614b5484546146c0565b84614ade565b602080601f831160018114614bad5760008415614b775750858301515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600386901b1c1916600185901b178555614b24565b6000858152602081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08616915b82811015614bfa57888601518255948401946001909101908401614bdb565b5085821015614c3657878501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600388901b60f8161c191681555b5050505050600190811b01905550565b60008251614c58818460208701614093565b919091019291505056fea26469706673582212200bfb0be60a592c669e79d483768719bea2aa6f04d756a989444646671fbb8a8564736f6c63430008100033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000d310a3041dfcf14def5ccbc508668974b5da7174
-----Decoded View---------------
Arg [0] : _manager (address): 0xd310A3041dFcF14Def5ccBc508668974b5da7174
-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 000000000000000000000000d310a3041dfcf14def5ccbc508668974b5da7174
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 34 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
Loading...
Loading
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.