Source Code
Overview
ETH Balance
0 ETH
More Info
ContractCreator
Multi Chain
Multichain Addresses
N/ALatest 1 from a total of 1 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
Value | ||||
---|---|---|---|---|---|---|---|---|---|
0x61020060 | 8486046 | 300 days 17 hrs ago | IN | Create: Governor | 0 ETH | 0.10083584 |
Latest 25 internal transactions (View All)
Advanced mode:
Parent Txn Hash | Block | From | To | Value | ||
---|---|---|---|---|---|---|
10187258 | 1 day 9 hrs ago | 0 ETH | ||||
10187251 | 1 day 9 hrs ago | 0 ETH | ||||
10187245 | 1 day 9 hrs ago | 0 ETH | ||||
10184743 | 1 day 20 hrs ago | 0 ETH | ||||
10158161 | 6 days 14 hrs ago | 0 ETH | ||||
10141039 | 9 days 13 hrs ago | 0 ETH | ||||
10141027 | 9 days 13 hrs ago | 0 ETH | ||||
10140983 | 9 days 13 hrs ago | 0 ETH | ||||
10140960 | 9 days 13 hrs ago | 0 ETH | ||||
10140844 | 9 days 14 hrs ago | 0 ETH | ||||
10140812 | 9 days 14 hrs ago | 0 ETH | ||||
10140755 | 9 days 14 hrs ago | 0 ETH | ||||
10140735 | 9 days 14 hrs ago | 0 ETH | ||||
10140392 | 9 days 16 hrs ago | 0 ETH | ||||
10140382 | 9 days 16 hrs ago | 0 ETH | ||||
10140309 | 9 days 16 hrs ago | 0 ETH | ||||
10140278 | 9 days 16 hrs ago | 0 ETH | ||||
10127257 | 11 days 23 hrs ago | 0 ETH | ||||
10122720 | 12 days 18 hrs ago | 0 ETH | ||||
10117867 | 13 days 15 hrs ago | 0 ETH | ||||
10117748 | 13 days 15 hrs ago | 0 ETH | ||||
10117724 | 13 days 15 hrs ago | 0 ETH | ||||
10115447 | 14 days 1 hr ago | 0 ETH | ||||
10113419 | 14 days 10 hrs ago | 0 ETH | ||||
10113388 | 14 days 10 hrs ago | 0 ETH |
Loading...
Loading
Contract Name:
Governor
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 { Ownable } from "../../lib/utils/Ownable.sol"; import { EIP712 } from "../../lib/utils/EIP712.sol"; import { SafeCast } from "../../lib/utils/SafeCast.sol"; import { GovernorStorageV1 } from "./storage/GovernorStorageV1.sol"; import { Token } from "../../token/Token.sol"; import { Treasury } from "../treasury/Treasury.sol"; import { IManager } from "../../manager/IManager.sol"; import { IGovernor } from "./IGovernor.sol"; import { ProposalHasher } from "./ProposalHasher.sol"; import { VersionedContract } from "../../VersionedContract.sol"; /// @title Governor /// @author Rohan Kulkarni /// @notice A DAO's proposal manager and transaction scheduler /// @custom:repo github.com/ourzora/nouns-protocol /// Modified from: /// - OpenZeppelin Contracts v4.7.3 (governance/extensions/GovernorTimelockControl.sol) /// - NounsDAOLogicV1.sol commit 2cbe6c7 - licensed under the BSD-3-Clause license. contract Governor is IGovernor, VersionedContract, UUPS, Ownable, EIP712, ProposalHasher, GovernorStorageV1 { /// /// /// IMMUTABLES /// /// /// /// @notice The EIP-712 typehash to vote with a signature bytes32 public immutable VOTE_TYPEHASH = keccak256("Vote(address voter,uint256 proposalId,uint256 support,uint256 nonce,uint256 deadline)"); /// @notice The minimum proposal threshold bps setting uint256 public immutable MIN_PROPOSAL_THRESHOLD_BPS = 1; /// @notice The maximum proposal threshold bps setting uint256 public immutable MAX_PROPOSAL_THRESHOLD_BPS = 1000; /// @notice The minimum quorum threshold bps setting uint256 public immutable MIN_QUORUM_THRESHOLD_BPS = 200; /// @notice The maximum quorum threshold bps setting uint256 public immutable MAX_QUORUM_THRESHOLD_BPS = 2000; /// @notice The minimum voting delay setting uint256 public immutable MIN_VOTING_DELAY = 1 seconds; /// @notice The maximum voting delay setting uint256 public immutable MAX_VOTING_DELAY = 24 weeks; /// @notice The minimum voting period setting uint256 public immutable MIN_VOTING_PERIOD = 10 minutes; /// @notice The maximum voting period setting uint256 public immutable MAX_VOTING_PERIOD = 24 weeks; /// @notice The basis points for 100% uint256 private immutable BPS_PER_100_PERCENT = 10_000; /// @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 governor /// @param _treasury The DAO's treasury address /// @param _token The DAO's governance token address /// @param _vetoer The address eligible to veto proposals /// @param _votingDelay The voting delay /// @param _votingPeriod The voting period /// @param _proposalThresholdBps The proposal threshold basis points /// @param _quorumThresholdBps The quorum threshold basis points function initialize( address _treasury, address _token, address _vetoer, uint256 _votingDelay, uint256 _votingPeriod, uint256 _proposalThresholdBps, uint256 _quorumThresholdBps ) external initializer { // Ensure the caller is the contract manager if (msg.sender != address(manager)) revert ONLY_MANAGER(); // Ensure non-zero addresses are provided if (_treasury == address(0)) revert ADDRESS_ZERO(); if (_token == address(0)) revert ADDRESS_ZERO(); // If a vetoer is specified, store its address if (_vetoer != address(0)) settings.vetoer = _vetoer; // Ensure the specified governance settings are valid if (_proposalThresholdBps < MIN_PROPOSAL_THRESHOLD_BPS || _proposalThresholdBps > MAX_PROPOSAL_THRESHOLD_BPS) revert INVALID_PROPOSAL_THRESHOLD_BPS(); if (_quorumThresholdBps < MIN_QUORUM_THRESHOLD_BPS || _quorumThresholdBps > MAX_QUORUM_THRESHOLD_BPS) revert INVALID_QUORUM_THRESHOLD_BPS(); if (_proposalThresholdBps >= _quorumThresholdBps) revert INVALID_PROPOSAL_THRESHOLD_BPS(); if (_votingDelay < MIN_VOTING_DELAY || _votingDelay > MAX_VOTING_DELAY) revert INVALID_VOTING_DELAY(); if (_votingPeriod < MIN_VOTING_PERIOD || _votingPeriod > MAX_VOTING_PERIOD) revert INVALID_VOTING_PERIOD(); // Store the governor settings settings.treasury = Treasury(payable(_treasury)); settings.token = Token(_token); settings.votingDelay = SafeCast.toUint48(_votingDelay); settings.votingPeriod = SafeCast.toUint48(_votingPeriod); settings.proposalThresholdBps = SafeCast.toUint16(_proposalThresholdBps); settings.quorumThresholdBps = SafeCast.toUint16(_quorumThresholdBps); // Initialize EIP-712 support __EIP712_init(string.concat(settings.token.symbol(), " GOV"), "1"); // Grant ownership to the treasury __Ownable_init(_treasury); } /// /// /// CREATE PROPOSAL /// /// /// /// @notice Creates a proposal /// @param _targets The target addresses to call /// @param _values The ETH values of each call /// @param _calldatas The calldata of each call /// @param _description The proposal description function propose( address[] memory _targets, uint256[] memory _values, bytes[] memory _calldatas, string memory _description ) external returns (bytes32) { // Get the current proposal threshold uint256 currentProposalThreshold = proposalThreshold(); // Cannot realistically underflow and `getVotes` would revert unchecked { // Ensure the caller's voting weight is greater than or equal to the threshold if (getVotes(msg.sender, block.timestamp - 1) <= proposalThreshold()) { revert BELOW_PROPOSAL_THRESHOLD(); } } // Cache the number of targets uint256 numTargets = _targets.length; // Ensure at least one target exists if (numTargets == 0) revert PROPOSAL_TARGET_MISSING(); // Ensure the number of targets matches the number of values and calldata if (numTargets != _values.length) revert PROPOSAL_LENGTH_MISMATCH(); if (numTargets != _calldatas.length) revert PROPOSAL_LENGTH_MISMATCH(); // Compute the description hash bytes32 descriptionHash = keccak256(bytes(_description)); // Compute the proposal id bytes32 proposalId = hashProposal(_targets, _values, _calldatas, descriptionHash, msg.sender); // Get the pointer to store the proposal Proposal storage proposal = proposals[proposalId]; // Ensure the proposal doesn't already exist if (proposal.voteStart != 0) revert PROPOSAL_EXISTS(proposalId); // Used to store the snapshot and deadline uint256 snapshot; uint256 deadline; // Cannot realistically overflow unchecked { // Compute the snapshot and deadline snapshot = block.timestamp + settings.votingDelay; deadline = snapshot + settings.votingPeriod; } // Store the proposal data proposal.voteStart = SafeCast.toUint32(snapshot); proposal.voteEnd = SafeCast.toUint32(deadline); proposal.proposalThreshold = SafeCast.toUint32(currentProposalThreshold); proposal.quorumVotes = SafeCast.toUint32(quorum()); proposal.proposer = msg.sender; proposal.timeCreated = SafeCast.toUint32(block.timestamp); emit ProposalCreated(proposalId, _targets, _values, _calldatas, _description, descriptionHash, proposal); return proposalId; } /// /// /// CAST VOTE /// /// /// /// @notice Casts a vote /// @param _proposalId The proposal id /// @param _support The support value (0 = Against, 1 = For, 2 = Abstain) function castVote(bytes32 _proposalId, uint256 _support) external returns (uint256) { return _castVote(_proposalId, msg.sender, _support, ""); } /// @notice Casts a vote with a reason /// @param _proposalId The proposal id /// @param _support The support value (0 = Against, 1 = For, 2 = Abstain) /// @param _reason The vote reason function castVoteWithReason( bytes32 _proposalId, uint256 _support, string memory _reason ) external returns (uint256) { return _castVote(_proposalId, msg.sender, _support, _reason); } /// @notice Casts a signed vote /// @param _voter The voter address /// @param _proposalId The proposal id /// @param _support The support value (0 = Against, 1 = For, 2 = Abstain) /// @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 castVoteBySig( address _voter, bytes32 _proposalId, uint256 _support, uint256 _deadline, uint8 _v, bytes32 _r, bytes32 _s ) external returns (uint256) { // Ensure the deadline has not passed if (block.timestamp > _deadline) revert EXPIRED_SIGNATURE(); // Used to store the signed digest bytes32 digest; // Cannot realistically overflow unchecked { // Compute the message digest = keccak256( abi.encodePacked( "\x19\x01", DOMAIN_SEPARATOR(), keccak256(abi.encode(VOTE_TYPEHASH, _voter, _proposalId, _support, nonces[_voter]++, _deadline)) ) ); } // Recover the message signer address recoveredAddress = ecrecover(digest, _v, _r, _s); // Ensure the recovered signer is the given voter if (recoveredAddress == address(0) || recoveredAddress != _voter) revert INVALID_SIGNATURE(); return _castVote(_proposalId, _voter, _support, ""); } /// @dev Stores a vote /// @param _proposalId The proposal id /// @param _voter The voter address /// @param _support The vote choice function _castVote( bytes32 _proposalId, address _voter, uint256 _support, string memory _reason ) internal returns (uint256) { // Ensure voting is active if (state(_proposalId) != ProposalState.Active) revert VOTING_NOT_STARTED(); // Ensure the voter hasn't already voted if (hasVoted[_proposalId][_voter]) revert ALREADY_VOTED(); // Ensure the vote is valid if (_support > 2) revert INVALID_VOTE(); // Record the voter as having voted hasVoted[_proposalId][_voter] = true; // Get the pointer to the proposal Proposal storage proposal = proposals[_proposalId]; // Used to store the voter's weight uint256 weight; // Cannot realistically underflow and `getVotes` would revert unchecked { // Get the voter's weight at the time the proposal was created weight = getVotes(_voter, proposal.timeCreated); // If the vote is against: if (_support == 0) { // Update the total number of votes against proposal.againstVotes += SafeCast.toUint32(weight); // Else if the vote is for: } else if (_support == 1) { // Update the total number of votes for proposal.forVotes += SafeCast.toUint32(weight); // Else if the vote is to abstain: } else if (_support == 2) { // Update the total number of votes abstaining proposal.abstainVotes += SafeCast.toUint32(weight); } } emit VoteCast(_voter, _proposalId, _support, weight, _reason); return weight; } /// /// /// QUEUE PROPOSAL /// /// /// /// @notice Queues a proposal /// @param _proposalId The proposal id function queue(bytes32 _proposalId) external returns (uint256 eta) { // Ensure the proposal has succeeded if (state(_proposalId) != ProposalState.Succeeded) revert PROPOSAL_UNSUCCESSFUL(); // Schedule the proposal for execution eta = settings.treasury.queue(_proposalId); emit ProposalQueued(_proposalId, eta); } /// /// /// EXECUTE PROPOSAL /// /// /// /// @notice Executes a proposal /// @param _targets The target addresses to call /// @param _values The ETH values of each call /// @param _calldatas The calldata of each call /// @param _descriptionHash The hash of the description /// @param _proposer The proposal creator function execute( address[] calldata _targets, uint256[] calldata _values, bytes[] calldata _calldatas, bytes32 _descriptionHash, address _proposer ) external payable returns (bytes32) { // Get the proposal id bytes32 proposalId = hashProposal(_targets, _values, _calldatas, _descriptionHash, _proposer); // Ensure the proposal is queued if (state(proposalId) != ProposalState.Queued) revert PROPOSAL_NOT_QUEUED(proposalId); // Mark the proposal as executed proposals[proposalId].executed = true; // Execute the proposal settings.treasury.execute{ value: msg.value }(_targets, _values, _calldatas, _descriptionHash, _proposer); emit ProposalExecuted(proposalId); return proposalId; } /// /// /// CANCEL PROPOSAL /// /// /// /// @notice Cancels a proposal /// @param _proposalId The proposal id function cancel(bytes32 _proposalId) external { // Ensure the proposal hasn't been executed if (state(_proposalId) == ProposalState.Executed) revert PROPOSAL_ALREADY_EXECUTED(); // Get a copy of the proposal Proposal memory proposal = proposals[_proposalId]; // Cannot realistically underflow and `getVotes` would revert unchecked { // Ensure the caller is the proposer or the proposer's voting weight has dropped below the proposal threshold if (msg.sender != proposal.proposer && getVotes(proposal.proposer, block.timestamp - 1) >= proposal.proposalThreshold) revert INVALID_CANCEL(); } // Update the proposal as canceled proposals[_proposalId].canceled = true; // If the proposal was queued: if (settings.treasury.isQueued(_proposalId)) { // Cancel the proposal settings.treasury.cancel(_proposalId); } emit ProposalCanceled(_proposalId); } /// /// /// VETO PROPOSAL /// /// /// /// @notice Vetoes a proposal /// @param _proposalId The proposal id function veto(bytes32 _proposalId) external { // Ensure the caller is the vetoer if (msg.sender != settings.vetoer) revert ONLY_VETOER(); // Ensure the proposal has not been executed if (state(_proposalId) == ProposalState.Executed) revert PROPOSAL_ALREADY_EXECUTED(); // Get the pointer to the proposal Proposal storage proposal = proposals[_proposalId]; // Update the proposal as vetoed proposal.vetoed = true; // If the proposal was queued: if (settings.treasury.isQueued(_proposalId)) { // Cancel the proposal settings.treasury.cancel(_proposalId); } emit ProposalVetoed(_proposalId); } /// /// /// PROPOSAL STATE /// /// /// /// @notice The state of a proposal /// @param _proposalId The proposal id function state(bytes32 _proposalId) public view returns (ProposalState) { // Get a copy of the proposal Proposal memory proposal = proposals[_proposalId]; // Ensure the proposal exists if (proposal.voteStart == 0) revert PROPOSAL_DOES_NOT_EXIST(); // If the proposal was executed: if (proposal.executed) { return ProposalState.Executed; // Else if the proposal was canceled: } else if (proposal.canceled) { return ProposalState.Canceled; // Else if the proposal was vetoed: } else if (proposal.vetoed) { return ProposalState.Vetoed; // Else if voting has not started: } else if (block.timestamp < proposal.voteStart) { return ProposalState.Pending; // Else if voting has not ended: } else if (block.timestamp < proposal.voteEnd) { return ProposalState.Active; // Else if the proposal failed (outvoted OR didn't reach quorum): } else if (proposal.forVotes <= proposal.againstVotes || proposal.forVotes < proposal.quorumVotes) { return ProposalState.Defeated; // Else if the proposal has not been queued: } else if (settings.treasury.timestamp(_proposalId) == 0) { return ProposalState.Succeeded; // Else if the proposal can no longer be executed: } else if (settings.treasury.isExpired(_proposalId)) { return ProposalState.Expired; // Else the proposal is queued } else { return ProposalState.Queued; } } /// @notice The voting weight of an account at a timestamp /// @param _account The account address /// @param _timestamp The specific timestamp function getVotes(address _account, uint256 _timestamp) public view returns (uint256) { return settings.token.getPastVotes(_account, _timestamp); } /// @notice The current number of votes required to submit a proposal function proposalThreshold() public view returns (uint256) { unchecked { return (settings.token.totalSupply() * settings.proposalThresholdBps) / BPS_PER_100_PERCENT; } } /// @notice The current number of votes required to be in favor of a proposal in order to reach quorum function quorum() public view returns (uint256) { unchecked { return (settings.token.totalSupply() * settings.quorumThresholdBps) / BPS_PER_100_PERCENT; } } /// @notice The data stored for a given proposal /// @param _proposalId The proposal id function getProposal(bytes32 _proposalId) external view returns (Proposal memory) { return proposals[_proposalId]; } /// @notice The timestamp when voting starts for a proposal /// @param _proposalId The proposal id function proposalSnapshot(bytes32 _proposalId) external view returns (uint256) { return proposals[_proposalId].voteStart; } /// @notice The timestamp when voting ends for a proposal /// @param _proposalId The proposal id function proposalDeadline(bytes32 _proposalId) external view returns (uint256) { return proposals[_proposalId].voteEnd; } /// @notice The vote counts for a proposal /// @param _proposalId The proposal id function proposalVotes(bytes32 _proposalId) external view returns ( uint256, uint256, uint256 ) { Proposal memory proposal = proposals[_proposalId]; return (proposal.againstVotes, proposal.forVotes, proposal.abstainVotes); } /// @notice The timestamp valid to execute a proposal /// @param _proposalId The proposal id function proposalEta(bytes32 _proposalId) external view returns (uint256) { return settings.treasury.timestamp(_proposalId); } /// /// /// GOVERNOR SETTINGS /// /// /// /// @notice The basis points of the token supply required to create a proposal function proposalThresholdBps() external view returns (uint256) { return settings.proposalThresholdBps; } /// @notice The basis points of the token supply required to reach quorum function quorumThresholdBps() external view returns (uint256) { return settings.quorumThresholdBps; } /// @notice The amount of time until voting begins after a proposal is created function votingDelay() external view returns (uint256) { return settings.votingDelay; } /// @notice The amount of time to vote on a proposal function votingPeriod() external view returns (uint256) { return settings.votingPeriod; } /// @notice The address eligible to veto any proposal (address(0) if burned) function vetoer() external view returns (address) { return settings.vetoer; } /// @notice The address of the governance token function token() external view returns (address) { return address(settings.token); } /// @notice The address of the treasury function treasury() external view returns (address) { return address(settings.treasury); } /// /// /// UPDATE SETTINGS /// /// /// /// @notice Updates the voting delay /// @param _newVotingDelay The new voting delay function updateVotingDelay(uint256 _newVotingDelay) external onlyOwner { if (_newVotingDelay < MIN_VOTING_DELAY || _newVotingDelay > MAX_VOTING_DELAY) revert INVALID_VOTING_DELAY(); emit VotingDelayUpdated(settings.votingDelay, _newVotingDelay); settings.votingDelay = uint48(_newVotingDelay); } /// @notice Updates the voting period /// @param _newVotingPeriod The new voting period function updateVotingPeriod(uint256 _newVotingPeriod) external onlyOwner { if (_newVotingPeriod < MIN_VOTING_PERIOD || _newVotingPeriod > MAX_VOTING_PERIOD) revert INVALID_VOTING_PERIOD(); emit VotingPeriodUpdated(settings.votingPeriod, _newVotingPeriod); settings.votingPeriod = uint48(_newVotingPeriod); } /// @notice Updates the minimum proposal threshold /// @param _newProposalThresholdBps The new proposal threshold basis points function updateProposalThresholdBps(uint256 _newProposalThresholdBps) external onlyOwner { if ( _newProposalThresholdBps < MIN_PROPOSAL_THRESHOLD_BPS || _newProposalThresholdBps > MAX_PROPOSAL_THRESHOLD_BPS || _newProposalThresholdBps >= settings.quorumThresholdBps ) revert INVALID_PROPOSAL_THRESHOLD_BPS(); emit ProposalThresholdBpsUpdated(settings.proposalThresholdBps, _newProposalThresholdBps); settings.proposalThresholdBps = uint16(_newProposalThresholdBps); } /// @notice Updates the minimum quorum threshold /// @param _newQuorumVotesBps The new quorum votes basis points function updateQuorumThresholdBps(uint256 _newQuorumVotesBps) external onlyOwner { if ( _newQuorumVotesBps < MIN_QUORUM_THRESHOLD_BPS || _newQuorumVotesBps > MAX_QUORUM_THRESHOLD_BPS || settings.proposalThresholdBps >= _newQuorumVotesBps ) revert INVALID_QUORUM_THRESHOLD_BPS(); emit QuorumVotesBpsUpdated(settings.quorumThresholdBps, _newQuorumVotesBps); settings.quorumThresholdBps = uint16(_newQuorumVotesBps); } /// @notice Updates the vetoer /// @param _newVetoer The new vetoer address function updateVetoer(address _newVetoer) external onlyOwner { if (_newVetoer == address(0)) revert ADDRESS_ZERO(); emit VetoerUpdated(settings.vetoer, _newVetoer); settings.vetoer = _newVetoer; } /// @notice Burns the vetoer function burnVetoer() external onlyOwner { emit VetoerUpdated(settings.vetoer, address(0)); delete settings.vetoer; } /// /// /// GOVERNOR 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 onlyOwner { // Ensure the new implementation is a registered upgrade 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.2.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; import { IUUPS } from "../../lib/interfaces/IUUPS.sol"; import { IOwnable } from "../../lib/utils/Ownable.sol"; import { IEIP712 } from "../../lib/utils/EIP712.sol"; import { GovernorTypesV1 } from "./types/GovernorTypesV1.sol"; import { IManager } from "../../manager/IManager.sol"; /// @title IGovernor /// @author Rohan Kulkarni /// @notice The external Governor events, errors and functions interface IGovernor is IUUPS, IOwnable, IEIP712, GovernorTypesV1 { /// /// /// EVENTS /// /// /// /// @notice Emitted when a proposal is created event ProposalCreated( bytes32 proposalId, address[] targets, uint256[] values, bytes[] calldatas, string description, bytes32 descriptionHash, Proposal proposal ); /// @notice Emitted when a proposal is queued event ProposalQueued(bytes32 proposalId, uint256 eta); /// @notice Emitted when a proposal is executed /// @param proposalId The proposal id event ProposalExecuted(bytes32 proposalId); /// @notice Emitted when a proposal is canceled event ProposalCanceled(bytes32 proposalId); /// @notice Emitted when a proposal is vetoed event ProposalVetoed(bytes32 proposalId); /// @notice Emitted when a vote is casted for a proposal event VoteCast(address voter, bytes32 proposalId, uint256 support, uint256 weight, string reason); /// @notice Emitted when the governor's voting delay is updated event VotingDelayUpdated(uint256 prevVotingDelay, uint256 newVotingDelay); /// @notice Emitted when the governor's voting period is updated event VotingPeriodUpdated(uint256 prevVotingPeriod, uint256 newVotingPeriod); /// @notice Emitted when the basis points of the governor's proposal threshold is updated event ProposalThresholdBpsUpdated(uint256 prevBps, uint256 newBps); /// @notice Emitted when the basis points of the governor's quorum votes is updated event QuorumVotesBpsUpdated(uint256 prevBps, uint256 newBps); //// @notice Emitted when the governor's vetoer is updated event VetoerUpdated(address prevVetoer, address newVetoer); /// /// /// ERRORS /// /// /// error INVALID_PROPOSAL_THRESHOLD_BPS(); error INVALID_QUORUM_THRESHOLD_BPS(); error INVALID_VOTING_DELAY(); error INVALID_VOTING_PERIOD(); /// @dev Reverts if a proposal already exists /// @param proposalId The proposal id error PROPOSAL_EXISTS(bytes32 proposalId); /// @dev Reverts if a proposal isn't queued /// @param proposalId The proposal id error PROPOSAL_NOT_QUEUED(bytes32 proposalId); /// @dev Reverts if the proposer didn't specify a target address error PROPOSAL_TARGET_MISSING(); /// @dev Reverts if the number of targets, values, and calldatas does not match error PROPOSAL_LENGTH_MISMATCH(); /// @dev Reverts if a proposal didn't succeed error PROPOSAL_UNSUCCESSFUL(); /// @dev Reverts if a proposal was already executed error PROPOSAL_ALREADY_EXECUTED(); /// @dev Reverts if a specified proposal doesn't exist error PROPOSAL_DOES_NOT_EXIST(); /// @dev Reverts if the proposer's voting weight is below the proposal threshold error BELOW_PROPOSAL_THRESHOLD(); /// @dev Reverts if a vote was prematurely casted error VOTING_NOT_STARTED(); /// @dev Reverts if the caller wasn't the vetoer error ONLY_VETOER(); /// @dev Reverts if the caller already voted error ALREADY_VOTED(); /// @dev Reverts if a proposal was attempted to be canceled incorrectly error INVALID_CANCEL(); /// @dev Reverts if a vote was attempted to be casted incorrectly error INVALID_VOTE(); /// @dev Reverts if the caller was not the contract manager error ONLY_MANAGER(); /// /// /// FUNCTIONS /// /// /// /// @notice Initializes a DAO's governor /// @param treasury The DAO's treasury address /// @param token The DAO's governance token address /// @param vetoer The address eligible to veto proposals /// @param votingDelay The voting delay /// @param votingPeriod The voting period /// @param proposalThresholdBps The proposal threshold basis points /// @param quorumThresholdBps The quorum threshold basis points function initialize( address treasury, address token, address vetoer, uint256 votingDelay, uint256 votingPeriod, uint256 proposalThresholdBps, uint256 quorumThresholdBps ) external; /// @notice Creates a proposal /// @param targets The target addresses to call /// @param values The ETH values of each call /// @param calldatas The calldata of each call /// @param description The proposal description function propose( address[] memory targets, uint256[] memory values, bytes[] memory calldatas, string memory description ) external returns (bytes32); /// @notice Casts a vote /// @param proposalId The proposal id /// @param support The support value (0 = Against, 1 = For, 2 = Abstain) function castVote(bytes32 proposalId, uint256 support) external returns (uint256); /// @notice Casts a vote with a reason /// @param proposalId The proposal id /// @param support The support value (0 = Against, 1 = For, 2 = Abstain) /// @param reason The vote reason function castVoteWithReason( bytes32 proposalId, uint256 support, string memory reason ) external returns (uint256); /// @notice Casts a signed vote /// @param voter The voter address /// @param proposalId The proposal id /// @param support The support value (0 = Against, 1 = For, 2 = Abstain) /// @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 castVoteBySig( address voter, bytes32 proposalId, uint256 support, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external returns (uint256); /// @notice Queues a proposal /// @param proposalId The proposal id function queue(bytes32 proposalId) external returns (uint256 eta); /// @notice Executes a proposal /// @param targets The target addresses to call /// @param values The ETH values of each call /// @param calldatas The calldata of each call /// @param descriptionHash The hash of the description /// @param proposer The proposal creator function execute( address[] memory targets, uint256[] memory values, bytes[] memory calldatas, bytes32 descriptionHash, address proposer ) external payable returns (bytes32); /// @notice Cancels a proposal /// @param proposalId The proposal id function cancel(bytes32 proposalId) external; /// @notice Vetoes a proposal /// @param proposalId The proposal id function veto(bytes32 proposalId) external; /// @notice The state of a proposal /// @param proposalId The proposal id function state(bytes32 proposalId) external view returns (ProposalState); /// @notice The voting weight of an account at a timestamp /// @param account The account address /// @param timestamp The specific timestamp function getVotes(address account, uint256 timestamp) external view returns (uint256); /// @notice The current number of votes required to submit a proposal function proposalThreshold() external view returns (uint256); /// @notice The current number of votes required to be in favor of a proposal in order to reach quorum function quorum() external view returns (uint256); /// @notice The details of a proposal /// @param proposalId The proposal id function getProposal(bytes32 proposalId) external view returns (Proposal memory); /// @notice The timestamp when voting starts for a proposal /// @param proposalId The proposal id function proposalSnapshot(bytes32 proposalId) external view returns (uint256); /// @notice The timestamp when voting ends for a proposal /// @param proposalId The proposal id function proposalDeadline(bytes32 proposalId) external view returns (uint256); /// @notice The vote counts for a proposal /// @param proposalId The proposal id function proposalVotes(bytes32 proposalId) external view returns ( uint256 againstVotes, uint256 forVotes, uint256 abstainVotes ); /// @notice The timestamp valid to execute a proposal /// @param proposalId The proposal id function proposalEta(bytes32 proposalId) external view returns (uint256); /// @notice The minimum basis points of the total token supply required to submit a proposal function proposalThresholdBps() external view returns (uint256); /// @notice The minimum basis points of the total token supply required to reach quorum function quorumThresholdBps() external view returns (uint256); /// @notice The amount of time until voting begins after a proposal is created function votingDelay() external view returns (uint256); /// @notice The amount of time to vote on a proposal function votingPeriod() external view returns (uint256); /// @notice The address eligible to veto any proposal (address(0) if burned) function vetoer() external view returns (address); /// @notice The address of the governance token function token() external view returns (address); /// @notice The address of the DAO treasury function treasury() external view returns (address); /// @notice Updates the voting delay /// @param newVotingDelay The new voting delay function updateVotingDelay(uint256 newVotingDelay) external; /// @notice Updates the voting period /// @param newVotingPeriod The new voting period function updateVotingPeriod(uint256 newVotingPeriod) external; /// @notice Updates the minimum proposal threshold /// @param newProposalThresholdBps The new proposal threshold basis points function updateProposalThresholdBps(uint256 newProposalThresholdBps) external; /// @notice Updates the minimum quorum threshold /// @param newQuorumVotesBps The new quorum votes basis points function updateQuorumThresholdBps(uint256 newQuorumVotesBps) external; /// @notice Updates the vetoer /// @param newVetoer The new vetoer addresss function updateVetoer(address newVetoer) external; /// @notice Burns the vetoer function burnVetoer() external; /// @notice The EIP-712 typehash to vote with a signature function VOTE_TYPEHASH() external view returns (bytes32); }
// SPDX-License-Identifier: MIT pragma solidity 0.8.16; /// @title ProposalHasher /// @author tbtstl /// @notice Helper contract to ensure proposal hashing functions are unified abstract contract ProposalHasher { /// /// /// HASH PROPOSAL /// /// /// /// @notice Hashes a proposal's details into a proposal id /// @param _targets The target addresses to call /// @param _values The ETH values of each call /// @param _calldatas The calldata of each call /// @param _descriptionHash The hash of the description /// @param _proposer The original proposer of the transaction function hashProposal( address[] memory _targets, uint256[] memory _values, bytes[] memory _calldatas, bytes32 _descriptionHash, address _proposer ) public pure returns (bytes32) { return keccak256(abi.encode(_targets, _values, _calldatas, _descriptionHash, _proposer)); } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.16; import { GovernorTypesV1 } from "../types/GovernorTypesV1.sol"; /// @title GovernorStorageV1 /// @author Rohan Kulkarni /// @notice The Governor storage contract contract GovernorStorageV1 is GovernorTypesV1 { /// @notice The governor settings Settings internal settings; /// @notice The details of a proposal /// @dev Proposal Id => Proposal mapping(bytes32 => Proposal) internal proposals; /// @notice If a user has voted on a proposal /// @dev Proposal Id => User => Has Voted mapping(bytes32 => mapping(address => bool)) internal hasVoted; }
// SPDX-License-Identifier: MIT pragma solidity 0.8.16; import { Token } from "../../../token/Token.sol"; import { Treasury } from "../../treasury/Treasury.sol"; /// @title GovernorTypesV1 /// @author Rohan Kulkarni /// @notice The Governor custom data types interface GovernorTypesV1 { /// @notice The governor settings /// @param token The DAO governance token /// @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 treasury The DAO treasury /// @param votingDelay The time delay to vote on a created proposal /// @param votingPeriod The time period to vote on a proposal /// @param vetoer The address with the ability to veto proposals struct Settings { Token token; uint16 proposalThresholdBps; uint16 quorumThresholdBps; Treasury treasury; uint48 votingDelay; uint48 votingPeriod; address vetoer; } /// @notice A governance proposal /// @param proposer The proposal creator /// @param timeCreated The timestamp that the proposal was created /// @param againstVotes The number of votes against /// @param forVotes The number of votes in favor /// @param abstainVotes The number of votes abstained /// @param voteStart The timestamp that voting starts /// @param voteEnd The timestamp that voting ends /// @param proposalThreshold The proposal threshold when the proposal was created /// @param quorumVotes The quorum threshold when the proposal was created /// @param executed If the proposal was executed /// @param canceled If the proposal was canceled /// @param vetoed If the proposal was vetoed struct Proposal { address proposer; uint32 timeCreated; uint32 againstVotes; uint32 forVotes; uint32 abstainVotes; uint32 voteStart; uint32 voteEnd; uint32 proposalThreshold; uint32 quorumVotes; bool executed; bool canceled; bool vetoed; } /// @notice The proposal state type enum ProposalState { Pending, Active, Canceled, Defeated, Succeeded, Queued, Expired, Executed, Vetoed } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.16; import { IOwnable } from "../../lib/utils/Ownable.sol"; import { IUUPS } from "../../lib/interfaces/IUUPS.sol"; /// @title ITreasury /// @author Rohan Kulkarni /// @notice The external Treasury events, errors and functions interface ITreasury is IUUPS, IOwnable { /// /// /// EVENTS /// /// /// /// @notice Emitted when a transaction is scheduled event TransactionScheduled(bytes32 proposalId, uint256 timestamp); /// @notice Emitted when a transaction is canceled event TransactionCanceled(bytes32 proposalId); /// @notice Emitted when a transaction is executed event TransactionExecuted(bytes32 proposalId, address[] targets, uint256[] values, bytes[] payloads); /// @notice Emitted when the transaction delay is updated event DelayUpdated(uint256 prevDelay, uint256 newDelay); /// @notice Emitted when the grace period is updated event GracePeriodUpdated(uint256 prevGracePeriod, uint256 newGracePeriod); /// /// /// ERRORS /// /// /// /// @dev Reverts if tx was already queued error PROPOSAL_ALREADY_QUEUED(); /// @dev Reverts if tx was not queued error PROPOSAL_NOT_QUEUED(); /// @dev Reverts if a tx isn't ready to execute /// @param proposalId The proposal id error EXECUTION_NOT_READY(bytes32 proposalId); /// @dev Reverts if a tx failed /// @param txIndex The index of the tx error EXECUTION_FAILED(uint256 txIndex); /// @dev Reverts if execution was attempted after the grace period error EXECUTION_EXPIRED(); /// @dev Reverts if the caller was not the treasury itself error ONLY_TREASURY(); /// @dev Reverts if the caller was not the contract manager error ONLY_MANAGER(); /// /// /// FUNCTIONS /// /// /// /// @notice Initializes a DAO's treasury /// @param governor The governor address /// @param timelockDelay The time delay to execute a queued transaction function initialize(address governor, uint256 timelockDelay) external; /// @notice The timestamp that a proposal is valid to execute /// @param proposalId The proposal id function timestamp(bytes32 proposalId) external view returns (uint256); /// @notice If a proposal has been queued /// @param proposalId The proposal ids function isQueued(bytes32 proposalId) external view returns (bool); /// @notice If a proposal is ready to execute (does not consider if a proposal has expired) /// @param proposalId The proposal id function isReady(bytes32 proposalId) external view returns (bool); /// @notice If a proposal has expired to execute /// @param proposalId The proposal id function isExpired(bytes32 proposalId) external view returns (bool); /// @notice Schedules a proposal for execution /// @param proposalId The proposal id function queue(bytes32 proposalId) external returns (uint256 eta); /// @notice Removes a queued proposal /// @param proposalId The proposal id function cancel(bytes32 proposalId) external; /// @notice Executes a queued proposal /// @param targets The target addresses to call /// @param values The ETH values of each call /// @param calldatas The calldata of each call /// @param descriptionHash The hash of the description /// @param proposer The proposal creator function execute( address[] calldata targets, uint256[] calldata values, bytes[] calldata calldatas, bytes32 descriptionHash, address proposer ) external payable; /// @notice The time delay to execute a queued transaction function delay() external view returns (uint256); /// @notice The time period to execute a transaction function gracePeriod() external view returns (uint256); /// @notice Updates the time delay /// @param newDelay The new time delay function updateDelay(uint256 newDelay) external; /// @notice Updates the grace period /// @param newGracePeriod The grace period function updateGracePeriod(uint256 newGracePeriod) external; }
// SPDX-License-Identifier: MIT pragma solidity 0.8.16; import { UUPS } from "../../lib/proxy/UUPS.sol"; import { Ownable } from "../../lib/utils/Ownable.sol"; import { ERC721TokenReceiver, ERC1155TokenReceiver } from "../../lib/utils/TokenReceiver.sol"; import { SafeCast } from "../../lib/utils/SafeCast.sol"; import { TreasuryStorageV1 } from "./storage/TreasuryStorageV1.sol"; import { ITreasury } from "./ITreasury.sol"; import { ProposalHasher } from "../governor/ProposalHasher.sol"; import { IManager } from "../../manager/IManager.sol"; import { VersionedContract } from "../../VersionedContract.sol"; /// @title Treasury /// @author Rohan Kulkarni /// @notice A DAO's treasury and transaction executor /// @custom:repo github.com/ourzora/nouns-protocol /// Modified from: /// - OpenZeppelin Contracts v4.7.3 (governance/TimelockController.sol) /// - NounsDAOExecutor.sol commit 2cbe6c7 - licensed under the BSD-3-Clause license. contract Treasury is ITreasury, VersionedContract, UUPS, Ownable, ProposalHasher, TreasuryStorageV1 { /// /// /// CONSTANTS /// /// /// /// @notice The default grace period setting uint128 private constant INITIAL_GRACE_PERIOD = 2 weeks; /// /// /// 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 an instance of a DAO's treasury /// @param _governor The DAO's governor address /// @param _delay The time delay to execute a queued transaction function initialize(address _governor, uint256 _delay) external initializer { // Ensure the caller is the contract manager if (msg.sender != address(manager)) revert ONLY_MANAGER(); // Ensure a governor address was provided if (_governor == address(0)) revert ADDRESS_ZERO(); // Grant ownership to the governor __Ownable_init(_governor); // Store the time delay settings.delay = SafeCast.toUint128(_delay); // Set the default grace period settings.gracePeriod = INITIAL_GRACE_PERIOD; emit DelayUpdated(0, _delay); } /// /// /// TRANSACTION STATE /// /// /// /// @notice The timestamp that a proposal is valid to execute /// @param _proposalId The proposal id function timestamp(bytes32 _proposalId) external view returns (uint256) { return timestamps[_proposalId]; } /// @notice If a queued proposal can no longer be executed /// @param _proposalId The proposal id function isExpired(bytes32 _proposalId) external view returns (bool) { unchecked { return block.timestamp > (timestamps[_proposalId] + settings.gracePeriod); } } /// @notice If a proposal is queued /// @param _proposalId The proposal id function isQueued(bytes32 _proposalId) public view returns (bool) { return timestamps[_proposalId] != 0; } /// @notice If a proposal is ready to execute (does not consider expiration) /// @param _proposalId The proposal id function isReady(bytes32 _proposalId) public view returns (bool) { return timestamps[_proposalId] != 0 && block.timestamp >= timestamps[_proposalId]; } /// /// /// QUEUE PROPOSAL /// /// /// /// @notice Schedules a proposal for execution /// @param _proposalId The proposal id function queue(bytes32 _proposalId) external onlyOwner returns (uint256 eta) { // Ensure the proposal was not already queued if (isQueued(_proposalId)) revert PROPOSAL_ALREADY_QUEUED(); // Cannot realistically overflow unchecked { // Compute the timestamp that the proposal will be valid to execute eta = block.timestamp + settings.delay; } // Store the timestamp timestamps[_proposalId] = eta; emit TransactionScheduled(_proposalId, eta); } /// /// /// EXECUTE PROPOSAL /// /// /// /// @notice Executes a queued proposal /// @param _targets The target addresses to call /// @param _values The ETH values of each call /// @param _calldatas The calldata of each call /// @param _descriptionHash The hash of the description /// @param _proposer The proposal creator function execute( address[] calldata _targets, uint256[] calldata _values, bytes[] calldata _calldatas, bytes32 _descriptionHash, address _proposer ) external payable onlyOwner { // Get the proposal id bytes32 proposalId = hashProposal(_targets, _values, _calldatas, _descriptionHash, _proposer); // Ensure the proposal is ready to execute if (!isReady(proposalId)) revert EXECUTION_NOT_READY(proposalId); // Remove the proposal from the queue delete timestamps[proposalId]; // Cache the number of targets uint256 numTargets = _targets.length; // Cannot realistically overflow unchecked { // For each target: for (uint256 i = 0; i < numTargets; ++i) { // Execute the transaction (bool success, ) = _targets[i].call{ value: _values[i] }(_calldatas[i]); // Ensure the transaction succeeded if (!success) revert EXECUTION_FAILED(i); } } emit TransactionExecuted(proposalId, _targets, _values, _calldatas); } /// /// /// CANCEL PROPOSAL /// /// /// /// @notice Removes a queued proposal /// @param _proposalId The proposal id function cancel(bytes32 _proposalId) external onlyOwner { // Ensure the proposal is queued if (!isQueued(_proposalId)) revert PROPOSAL_NOT_QUEUED(); // Remove the proposal from the queue delete timestamps[_proposalId]; emit TransactionCanceled(_proposalId); } /// /// /// TREASURY SETTINGS /// /// /// /// @notice The time delay to execute a queued transaction function delay() external view returns (uint256) { return settings.delay; } /// @notice The time period to execute a proposal function gracePeriod() external view returns (uint256) { return settings.gracePeriod; } /// /// /// UPDATE SETTINGS /// /// /// /// @notice Updates the transaction delay /// @param _newDelay The new time delay function updateDelay(uint256 _newDelay) external { // Ensure the caller is the treasury itself if (msg.sender != address(this)) revert ONLY_TREASURY(); emit DelayUpdated(settings.delay, _newDelay); // Update the delay settings.delay = SafeCast.toUint128(_newDelay); } /// @notice Updates the execution grace period /// @param _newGracePeriod The new grace period function updateGracePeriod(uint256 _newGracePeriod) external { // Ensure the caller is the treasury itself if (msg.sender != address(this)) revert ONLY_TREASURY(); emit GracePeriodUpdated(settings.gracePeriod, _newGracePeriod); // Update the grace period settings.gracePeriod = SafeCast.toUint128(_newGracePeriod); } /// /// /// RECEIVE TOKENS /// /// /// /// @dev Accepts all ERC-721 transfers function onERC721Received( address, address, uint256, bytes memory ) public pure returns (bytes4) { return ERC721TokenReceiver.onERC721Received.selector; } /// @dev Accepts all ERC-1155 single id transfers function onERC1155Received( address, address, uint256, uint256, bytes memory ) public pure returns (bytes4) { return ERC1155TokenReceiver.onERC1155Received.selector; } /// @dev Accept all ERC-1155 batch id transfers function onERC1155BatchReceived( address, address, uint256[] memory, uint256[] memory, bytes memory ) public pure returns (bytes4) { return ERC1155TokenReceiver.onERC1155BatchReceived.selector; } /// @dev Accepts ETH transfers receive() external payable {} /// /// /// TREASURY 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 treasury itself if (msg.sender != address(this)) revert ONLY_TREASURY(); // Ensure the new implementation is a registered upgrade if (!manager.isRegisteredUpgrade(_getImplementation(), _newImpl)) revert INVALID_UPGRADE(_newImpl); } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.16; import { TreasuryTypesV1 } from "../types/TreasuryTypesV1.sol"; /// @notice TreasuryStorageV1 /// @author Rohan Kulkarni /// @notice The Treasury storage contract contract TreasuryStorageV1 is TreasuryTypesV1 { /// @notice The treasury settings Settings internal settings; /// @notice The timestamp that a queued proposal is ready to execute /// @dev Proposal Id => Timestamp mapping(bytes32 => uint256) internal timestamps; }
// SPDX-License-Identifier: MIT pragma solidity 0.8.16; /// @notice TreasuryTypesV1 /// @author Rohan Kulkarni /// @notice The treasury's custom data types contract TreasuryTypesV1 { /// @notice The settings type /// @param gracePeriod The time period to execute a proposal /// @param delay The time delay to execute a queued transaction struct Settings { uint128 gracePeriod; uint128 delay; } }
// 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.16; /// @notice Modified from OpenZeppelin Contracts v4.7.3 (utils/math/SafeCast.sol) /// - Uses custom error `UNSAFE_CAST()` library SafeCast { error UNSAFE_CAST(); function toUint128(uint256 x) internal pure returns (uint128) { if (x > type(uint128).max) revert UNSAFE_CAST(); return uint128(x); } function toUint64(uint256 x) internal pure returns (uint64) { if (x > type(uint64).max) revert UNSAFE_CAST(); return uint64(x); } function toUint48(uint256 x) internal pure returns (uint48) { if (x > type(uint48).max) revert UNSAFE_CAST(); return uint48(x); } function toUint40(uint256 x) internal pure returns (uint40) { if (x > type(uint40).max) revert UNSAFE_CAST(); return uint40(x); } function toUint32(uint256 x) internal pure returns (uint32) { if (x > type(uint32).max) revert UNSAFE_CAST(); return uint32(x); } function toUint16(uint256 x) internal pure returns (uint16) { if (x > type(uint16).max) revert UNSAFE_CAST(); return uint16(x); } function toUint8(uint256 x) internal pure returns (uint8) { if (x > type(uint8).max) revert UNSAFE_CAST(); return uint8(x); } }
// 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"; import { TokenTypesV2 } from "./types/TokenTypesV2.sol"; /// @title IToken /// @author Rohan Kulkarni /// @notice The external Token events, errors and functions interface IToken is IUUPS, IERC721Votes, TokenTypesV1, TokenTypesV2 { /// /// /// 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); /// @notice Emitted when minters are updated /// @param minter Address of added or removed minter /// @param allowed Whether address is allowed to mint event MinterUpdated(address minter, bool allowed); /// /// /// 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 the caller was not a minter error ONLY_AUCTION_OR_MINTER(); /// @dev Reverts if the caller was not the token owner error ONLY_TOKEN_OWNER(); /// @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 caller and handles founder vesting function mint() external returns (uint256 tokenId); /// @notice Mints tokens to the recipient and handles founder vesting function mintTo(address recipient) external returns (uint256 tokenId); /// @notice Mints the specified amount of tokens to the recipient and handles founder vesting function mintBatchTo(uint256 amount, address recipient) external returns (uint256[] memory tokenIds); /// @notice Burns a token owned by the caller /// @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 Update minters /// @param _minters Array of structs containing address status as a minter function updateMinters(MinterParams[] calldata _minters) external; /// @notice Check if an address is a minter /// @param _minter Address to check function isMinter(address _minter) external view returns (bool); /// @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 { 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 { TokenStorageV2 } from "./storage/TokenStorageV2.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, TokenStorageV2 { /// /// /// IMMUTABLES /// /// /// /// @notice The contract upgrade manager IManager private immutable manager; /// /// /// MODIFIERS /// /// /// /// @notice Reverts if caller is not an authorized minter modifier onlyAuctionOrMinter() { if (msg.sender != settings.auction && !minter[msg.sender]) { revert ONLY_AUCTION_OR_MINTER(); } _; } /// /// /// 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 caller and handles founder vesting function mint() external nonReentrant onlyAuctionOrMinter returns (uint256 tokenId) { tokenId = _mintWithVesting(msg.sender); } /// @notice Mints tokens to the recipient and handles founder vesting function mintTo(address recipient) external nonReentrant onlyAuctionOrMinter returns (uint256 tokenId) { tokenId = _mintWithVesting(recipient); } /// @notice Mints the specified amount of tokens to the recipient and handles founder vesting function mintBatchTo(uint256 amount, address recipient) external nonReentrant onlyAuctionOrMinter returns (uint256[] memory tokenIds) { tokenIds = new uint256[](amount); for (uint256 i = 0; i < amount; ) { tokenIds[i] = _mintWithVesting(recipient); unchecked { ++i; } } } function _mintWithVesting(address recipient) internal returns (uint256 tokenId) { // 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 recipient for bidding _mint(recipient, 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 owned by the caller /// @param _tokenId The ERC-721 token id function burn(uint256 _tokenId) external onlyAuctionOrMinter { if (ownerOf(_tokenId) != msg.sender) { revert ONLY_TOKEN_OWNER(); } _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(); } /// @notice Update minters /// @param _minters Array of structs containing address status as a minter function updateMinters(MinterParams[] calldata _minters) external onlyOwner { // Update each minter for (uint256 i; i < _minters.length; ++i) { // Skip if the minter is already set to the correct value if (minter[_minters[i].minter] == _minters[i].allowed) continue; emit MinterUpdated(_minters[i].minter, _minters[i].allowed); // Update the minter minter[_minters[i].minter] = _minters[i].allowed; } } /// @notice Check if an address is a minter /// @param _minter Address to check function isMinter(address _minter) external view returns (bool) { return minter[_minter]; } /// /// /// 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 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 { TokenTypesV2 } from "../types/TokenTypesV2.sol"; /// @title TokenStorageV2 /// @author James Geary /// @notice The Token storage contract contract TokenStorageV2 is TokenTypesV2 { /// @notice The minter status of an address mapping(address => bool) public minter; }
// 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; } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.16; /// @title TokenTypesV2 /// @author James Geary /// @notice The Token custom data types interface TokenTypesV2 { struct MinterParams { address minter; bool allowed; } }
{ "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": {} }
[{"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_VOTED","type":"error"},{"inputs":[],"name":"BELOW_PROPOSAL_THRESHOLD","type":"error"},{"inputs":[],"name":"DELEGATE_CALL_FAILED","type":"error"},{"inputs":[],"name":"EXPIRED_SIGNATURE","type":"error"},{"inputs":[],"name":"INITIALIZING","type":"error"},{"inputs":[],"name":"INVALID_CANCEL","type":"error"},{"inputs":[],"name":"INVALID_PROPOSAL_THRESHOLD_BPS","type":"error"},{"inputs":[],"name":"INVALID_QUORUM_THRESHOLD_BPS","type":"error"},{"inputs":[],"name":"INVALID_SIGNATURE","type":"error"},{"inputs":[],"name":"INVALID_TARGET","type":"error"},{"inputs":[{"internalType":"address","name":"impl","type":"address"}],"name":"INVALID_UPGRADE","type":"error"},{"inputs":[],"name":"INVALID_VOTE","type":"error"},{"inputs":[],"name":"INVALID_VOTING_DELAY","type":"error"},{"inputs":[],"name":"INVALID_VOTING_PERIOD","type":"error"},{"inputs":[],"name":"NOT_INITIALIZING","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":"ONLY_VETOER","type":"error"},{"inputs":[],"name":"PROPOSAL_ALREADY_EXECUTED","type":"error"},{"inputs":[],"name":"PROPOSAL_DOES_NOT_EXIST","type":"error"},{"inputs":[{"internalType":"bytes32","name":"proposalId","type":"bytes32"}],"name":"PROPOSAL_EXISTS","type":"error"},{"inputs":[],"name":"PROPOSAL_LENGTH_MISMATCH","type":"error"},{"inputs":[{"internalType":"bytes32","name":"proposalId","type":"bytes32"}],"name":"PROPOSAL_NOT_QUEUED","type":"error"},{"inputs":[],"name":"PROPOSAL_TARGET_MISSING","type":"error"},{"inputs":[],"name":"PROPOSAL_UNSUCCESSFUL","type":"error"},{"inputs":[],"name":"UNSAFE_CAST","type":"error"},{"inputs":[],"name":"UNSUPPORTED_UUID","type":"error"},{"inputs":[],"name":"VOTING_NOT_STARTED","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"version","type":"uint256"}],"name":"Initialized","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":false,"internalType":"bytes32","name":"proposalId","type":"bytes32"}],"name":"ProposalCanceled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"proposalId","type":"bytes32"},{"indexed":false,"internalType":"address[]","name":"targets","type":"address[]"},{"indexed":false,"internalType":"uint256[]","name":"values","type":"uint256[]"},{"indexed":false,"internalType":"bytes[]","name":"calldatas","type":"bytes[]"},{"indexed":false,"internalType":"string","name":"description","type":"string"},{"indexed":false,"internalType":"bytes32","name":"descriptionHash","type":"bytes32"},{"components":[{"internalType":"address","name":"proposer","type":"address"},{"internalType":"uint32","name":"timeCreated","type":"uint32"},{"internalType":"uint32","name":"againstVotes","type":"uint32"},{"internalType":"uint32","name":"forVotes","type":"uint32"},{"internalType":"uint32","name":"abstainVotes","type":"uint32"},{"internalType":"uint32","name":"voteStart","type":"uint32"},{"internalType":"uint32","name":"voteEnd","type":"uint32"},{"internalType":"uint32","name":"proposalThreshold","type":"uint32"},{"internalType":"uint32","name":"quorumVotes","type":"uint32"},{"internalType":"bool","name":"executed","type":"bool"},{"internalType":"bool","name":"canceled","type":"bool"},{"internalType":"bool","name":"vetoed","type":"bool"}],"indexed":false,"internalType":"struct GovernorTypesV1.Proposal","name":"proposal","type":"tuple"}],"name":"ProposalCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"proposalId","type":"bytes32"}],"name":"ProposalExecuted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"proposalId","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"eta","type":"uint256"}],"name":"ProposalQueued","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"prevBps","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newBps","type":"uint256"}],"name":"ProposalThresholdBpsUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"proposalId","type":"bytes32"}],"name":"ProposalVetoed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"prevBps","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newBps","type":"uint256"}],"name":"QuorumVotesBpsUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"impl","type":"address"}],"name":"Upgraded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"prevVetoer","type":"address"},{"indexed":false,"internalType":"address","name":"newVetoer","type":"address"}],"name":"VetoerUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"voter","type":"address"},{"indexed":false,"internalType":"bytes32","name":"proposalId","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"support","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"weight","type":"uint256"},{"indexed":false,"internalType":"string","name":"reason","type":"string"}],"name":"VoteCast","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"prevVotingDelay","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newVotingDelay","type":"uint256"}],"name":"VotingDelayUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"prevVotingPeriod","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newVotingPeriod","type":"uint256"}],"name":"VotingPeriodUpdated","type":"event"},{"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_PROPOSAL_THRESHOLD_BPS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_QUORUM_THRESHOLD_BPS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_VOTING_DELAY","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_VOTING_PERIOD","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_PROPOSAL_THRESHOLD_BPS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_QUORUM_THRESHOLD_BPS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_VOTING_DELAY","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_VOTING_PERIOD","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"VOTE_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"burnVetoer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_proposalId","type":"bytes32"}],"name":"cancel","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"cancelOwnershipTransfer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_proposalId","type":"bytes32"},{"internalType":"uint256","name":"_support","type":"uint256"}],"name":"castVote","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_voter","type":"address"},{"internalType":"bytes32","name":"_proposalId","type":"bytes32"},{"internalType":"uint256","name":"_support","type":"uint256"},{"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":"castVoteBySig","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_proposalId","type":"bytes32"},{"internalType":"uint256","name":"_support","type":"uint256"},{"internalType":"string","name":"_reason","type":"string"}],"name":"castVoteWithReason","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"contractVersion","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address[]","name":"_targets","type":"address[]"},{"internalType":"uint256[]","name":"_values","type":"uint256[]"},{"internalType":"bytes[]","name":"_calldatas","type":"bytes[]"},{"internalType":"bytes32","name":"_descriptionHash","type":"bytes32"},{"internalType":"address","name":"_proposer","type":"address"}],"name":"execute","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_proposalId","type":"bytes32"}],"name":"getProposal","outputs":[{"components":[{"internalType":"address","name":"proposer","type":"address"},{"internalType":"uint32","name":"timeCreated","type":"uint32"},{"internalType":"uint32","name":"againstVotes","type":"uint32"},{"internalType":"uint32","name":"forVotes","type":"uint32"},{"internalType":"uint32","name":"abstainVotes","type":"uint32"},{"internalType":"uint32","name":"voteStart","type":"uint32"},{"internalType":"uint32","name":"voteEnd","type":"uint32"},{"internalType":"uint32","name":"proposalThreshold","type":"uint32"},{"internalType":"uint32","name":"quorumVotes","type":"uint32"},{"internalType":"bool","name":"executed","type":"bool"},{"internalType":"bool","name":"canceled","type":"bool"},{"internalType":"bool","name":"vetoed","type":"bool"}],"internalType":"struct GovernorTypesV1.Proposal","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"},{"internalType":"uint256","name":"_timestamp","type":"uint256"}],"name":"getVotes","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"_targets","type":"address[]"},{"internalType":"uint256[]","name":"_values","type":"uint256[]"},{"internalType":"bytes[]","name":"_calldatas","type":"bytes[]"},{"internalType":"bytes32","name":"_descriptionHash","type":"bytes32"},{"internalType":"address","name":"_proposer","type":"address"}],"name":"hashProposal","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"_treasury","type":"address"},{"internalType":"address","name":"_token","type":"address"},{"internalType":"address","name":"_vetoer","type":"address"},{"internalType":"uint256","name":"_votingDelay","type":"uint256"},{"internalType":"uint256","name":"_votingPeriod","type":"uint256"},{"internalType":"uint256","name":"_proposalThresholdBps","type":"uint256"},{"internalType":"uint256","name":"_quorumThresholdBps","type":"uint256"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"nonce","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_proposalId","type":"bytes32"}],"name":"proposalDeadline","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_proposalId","type":"bytes32"}],"name":"proposalEta","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_proposalId","type":"bytes32"}],"name":"proposalSnapshot","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"proposalThreshold","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"proposalThresholdBps","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_proposalId","type":"bytes32"}],"name":"proposalVotes","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"_targets","type":"address[]"},{"internalType":"uint256[]","name":"_values","type":"uint256[]"},{"internalType":"bytes[]","name":"_calldatas","type":"bytes[]"},{"internalType":"string","name":"_description","type":"string"}],"name":"propose","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"proxiableUUID","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_proposalId","type":"bytes32"}],"name":"queue","outputs":[{"internalType":"uint256","name":"eta","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"quorum","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"quorumThresholdBps","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_newOwner","type":"address"}],"name":"safeTransferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_proposalId","type":"bytes32"}],"name":"state","outputs":[{"internalType":"enum GovernorTypesV1.ProposalState","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"token","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"treasury","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_newProposalThresholdBps","type":"uint256"}],"name":"updateProposalThresholdBps","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_newQuorumVotesBps","type":"uint256"}],"name":"updateQuorumThresholdBps","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newVetoer","type":"address"}],"name":"updateVetoer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_newVotingDelay","type":"uint256"}],"name":"updateVotingDelay","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_newVotingPeriod","type":"uint256"}],"name":"updateVotingPeriod","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"},{"inputs":[{"internalType":"bytes32","name":"_proposalId","type":"bytes32"}],"name":"veto","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"vetoer","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"votingDelay","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"votingPeriod","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]
Contract Creation Code
6102006040819052306080527f4b87515bde17bd1a40e570a7c028fa4b7e66dd1ed9dc7c0cd8fd78d67ca34f2860a052600160c08190526103e860e05260c8610100526107d0610120526101405262dd7c00610160819052610258610180526101a0526127106101c052620059ad3881900390819083398101604081905262000088916200017c565b600054610100900460ff1615801580620000a6575060005460ff1615155b8015620000d65750620000c4306200017660201b62003c141760201c565b80620000d6575060005460ff16600114155b15620000f55760405163439a74c960e01b815260040160405180910390fd5b6000805460ff19166001179055801562000119576000805461ff0019166101001790555b6001600160a01b0382166101e05280156200016e576000805461ff0019169055604051600181527fbe9b076dc5b65990cca9dd9d7366682482e7817a6f6bc7f4faf4dc32af497f329060200160405180910390a15b5050620001ae565b3b151590565b6000602082840312156200018f57600080fd5b81516001600160a01b0381168114620001a757600080fd5b9392505050565b60805160a05160c05160e05161010051610120516101405161016051610180516101a0516101c0516101e0516156cc620002e1600039600081816112ff0152613e7f015260008181610f1f0152612d38015260008181610a650152818161163d015261386501526000818161045f01528181611614015261383c015260008181610ab9015281816115b901526124bb015260008181610dcd015281816115900152612492015260008181610e81015281816114fc01526136b80152600081816103ab015281816114d3015261368f01526000818161042b015281816114780152613471015260008181610b420152818161144f01526134480152600081816109940152612e35015260008181611a8501528181611adf01528181611cc701528181611d210152611e1401526156cc6000f3fe60806040526004361061034a5760003560e01c806379ba5097116101bb578063c82fbd08116100f7578063eb9019d411610095578063f2fde38b1161006f578063f2fde38b14610e4f578063f990b49114610e6f578063fb6f93f914610ea3578063fc0c546a14610ec357600080fd5b8063eb9019d414610def578063ebfdeacf14610e0f578063ef00ef4314610e2f57600080fd5b8063d8bff440116100d1578063d8bff44014610d45578063e30c397814610d70578063e42eb4f614610d9b578063e48083fe14610dbb57600080fd5b8063c82fbd0814610b30578063cbcda20114610b64578063d14b85b914610ba257600080fd5b8063a0a8e46011610164578063b11262631161013e578063b112626314610aa7578063b58131b014610adb578063c3e5178914610af0578063c4d252f514610b1057600080fd5b8063a0a8e46014610a07578063a64e024a14610a53578063aedbfe3314610a8757600080fd5b8063865229731161019557806386522973146109825780638da5cb5b146109b65780639dcbfd7d146109e757600080fd5b806379ba50971461092d5780637c10dea6146109425780637d5e81e21461096257600080fd5b80633bec7f5b1161028a57806352d1902d1161023357806361d585da1161020d57806361d585da1461087d57806363d61a19146108aa57806370ae92d2146108ca57806375a12d721461090d57600080fd5b806352d1902d1461080957806360e69a7b1461081e57806361d027b31461083157600080fd5b8063430694cf11610264578063430694cf146105d557806348b1aeb4146107c55780634f1ef286146107f657600080fd5b80633bec7f5b146105405780633d24375f1461057357806341f9b62c146105b557600080fd5b8063215809ca116102f75780633644e515116102d15780633644e515146104b65780633659cfe6146104cb5780633932abb1146104eb578063395db2cd1461052057600080fd5b8063215809ca1461044d57806323452b9c146104815780632b4656c81461049657600080fd5b8063177e5a9f11610328578063177e5a9f146103e25780631e5cc3bd146104025780631e7b5d3a1461041957600080fd5b806302a251a31461034f578063032bbc53146103995780631703a018146103cd575b600080fd5b34801561035b57600080fd5b506008547a010000000000000000000000000000000000000000000000000000900465ffffffffffff165b6040519081526020015b60405180910390f35b3480156103a557600080fd5b506103867f000000000000000000000000000000000000000000000000000000000000000081565b3480156103d957600080fd5b50610386610eee565b3480156103ee57600080fd5b506103866103fd366004614777565b610fda565b34801561040e57600080fd5b50610417611074565b005b34801561042557600080fd5b506103867f000000000000000000000000000000000000000000000000000000000000000081565b34801561045957600080fd5b506103867f000000000000000000000000000000000000000000000000000000000000000081565b34801561048d57600080fd5b50610417611147565b3480156104a257600080fd5b506104176104b13660046147b9565b611219565b3480156104c257600080fd5b506103866119eb565b3480156104d757600080fd5b506104176104e6366004614821565b611a6e565b3480156104f757600080fd5b5060085474010000000000000000000000000000000000000000900465ffffffffffff16610386565b34801561052c57600080fd5b5061041761053b366004614821565b611bc6565b34801561054c57600080fd5b50600754760100000000000000000000000000000000000000000000900461ffff16610386565b34801561057f57600080fd5b5061038661058e366004614777565b6000908152600a602052604090206001015468010000000000000000900463ffffffff1690565b3480156105c157600080fd5b506103866105d0366004614956565b611c9a565b3480156105e157600080fd5b506107b86105f0366004614777565b6040805161018081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e08101829052610100810182905261012081018290526101408101829052610160810191909152506000908152600a6020908152604091829020825161018081018452815473ffffffffffffffffffffffffffffffffffffffff8116825263ffffffff74010000000000000000000000000000000000000000808304821695840195909552780100000000000000000000000000000000000000000000000082048116958301959095527c010000000000000000000000000000000000000000000000000000000090048416606082015260019091015480841660808301526401000000008104841660a0830152680100000000000000008104841660c08301526c010000000000000000000000008104841660e0830152700100000000000000000000000000000000810490931661010082015260ff91830482161515610120820152750100000000000000000000000000000000000000000083048216151561014082015276010000000000000000000000000000000000000000000090920416151561016082015290565b60405161039091906149a6565b3480156107d157600080fd5b5060075474010000000000000000000000000000000000000000900461ffff16610386565b610417610804366004614aac565b611cb0565b34801561081557600080fd5b50610386611dfa565b61038661082c366004614b46565b611e90565b34801561083d57600080fd5b5060085473ffffffffffffffffffffffffffffffffffffffff165b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610390565b34801561088957600080fd5b5061089d610898366004614777565b612098565b6040516103909190614c28565b3480156108b657600080fd5b506104176108c5366004614777565b612439565b3480156108d657600080fd5b506103866108e5366004614821565b73ffffffffffffffffffffffffffffffffffffffff1660009081526006602052604090205490565b34801561091957600080fd5b50610386610928366004614c69565b6125c1565b34801561093957600080fd5b506104176125e5565b34801561094e57600080fd5b5061038661095d366004614777565b6126ef565b34801561096e57600080fd5b5061038661097d366004614e0b565b61281a565b34801561098e57600080fd5b506103867f000000000000000000000000000000000000000000000000000000000000000081565b3480156109c257600080fd5b5060005462010000900473ffffffffffffffffffffffffffffffffffffffff16610858565b3480156109f357600080fd5b50610417610a02366004614821565b612b8d565b348015610a1357600080fd5b50604080518082018252600581527f312e322e30000000000000000000000000000000000000000000000000000000602082015290516103909190614f26565b348015610a5f57600080fd5b506103867f000000000000000000000000000000000000000000000000000000000000000081565b348015610a9357600080fd5b50610386610aa2366004614f39565b612ccb565b348015610ab357600080fd5b506103867f000000000000000000000000000000000000000000000000000000000000000081565b348015610ae757600080fd5b50610386612d07565b348015610afc57600080fd5b50610386610b0b366004614fdc565b612db9565b348015610b1c57600080fd5b50610417610b2b366004614777565b613030565b348015610b3c57600080fd5b506103867f000000000000000000000000000000000000000000000000000000000000000081565b348015610b7057600080fd5b50610386610b7f366004614777565b6000908152600a6020526040902060010154640100000000900463ffffffff1690565b348015610bae57600080fd5b50610d2a610bbd366004614777565b6000908152600a6020908152604091829020825161018081018452815473ffffffffffffffffffffffffffffffffffffffff8116825263ffffffff740100000000000000000000000000000000000000008083048216958401959095527801000000000000000000000000000000000000000000000000820481169583018690527c0100000000000000000000000000000000000000000000000000000000909104811660608301819052600190930154808216608084018190526401000000008204831660a0850152680100000000000000008204831660c08501526c010000000000000000000000008204831660e0850152700100000000000000000000000000000000820490921661010084015260ff94810485161515610120840152750100000000000000000000000000000000000000000081048516151561014084015276010000000000000000000000000000000000000000000090049093161515610160909101529192565b60408051938452602084019290925290820152606001610390565b348015610d5157600080fd5b5060095473ffffffffffffffffffffffffffffffffffffffff16610858565b348015610d7c57600080fd5b5060015473ffffffffffffffffffffffffffffffffffffffff16610858565b348015610da757600080fd5b50610417610db6366004614777565b6133ef565b348015610dc757600080fd5b506103867f000000000000000000000000000000000000000000000000000000000000000081565b348015610dfb57600080fd5b50610386610e0a366004615048565b61359a565b348015610e1b57600080fd5b50610417610e2a366004614777565b613636565b348015610e3b57600080fd5b50610417610e4a366004614777565b6137e3565b348015610e5b57600080fd5b50610417610e6a366004614821565b613971565b348015610e7b57600080fd5b506103867f000000000000000000000000000000000000000000000000000000000000000081565b348015610eaf57600080fd5b50610417610ebe366004614777565b6139d1565b348015610ecf57600080fd5b5060075473ffffffffffffffffffffffffffffffffffffffff16610858565b600754604080517f18160ddd00000000000000000000000000000000000000000000000000000000815290516000927f00000000000000000000000000000000000000000000000000000000000000009261ffff7601000000000000000000000000000000000000000000008304169273ffffffffffffffffffffffffffffffffffffffff909216916318160ddd916004808201926020929091908290030181865afa158015610fa2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fc69190615072565b0281610fd457610fd461508b565b04905090565b6008546040517f4d0030700000000000000000000000000000000000000000000000000000000081526004810183905260009173ffffffffffffffffffffffffffffffffffffffff1690634d00307090602401602060405180830381865afa15801561104a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061106e9190615072565b92915050565b60005462010000900473ffffffffffffffffffffffffffffffffffffffff1633146110cb576040517fd238ed5900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6009546040805173ffffffffffffffffffffffffffffffffffffffff9092168252600060208301527e36bea9286cc431052f56dee1918d8a6665ef6f6370e6b4d71b7deaac1d0556910160405180910390a1600980547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055565b60005462010000900473ffffffffffffffffffffffffffffffffffffffff16331461119e576040517fd238ed5900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001546000805460405173ffffffffffffffffffffffffffffffffffffffff9384169362010000909204909116917f682679deecef4dcd49674845cc1e3a075fea9073680aa445a8207d5a4bdea3da91a3600180547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055565b600054610100900460ff1615801580611236575060005460ff1615155b80156112525750303b151580611252575060005460ff16600114155b15611289576040517f439a74c900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905580156112e757600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614611356576040517fa2ddd97100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff88166113a3576040517f66e7950900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff87166113f0576040517f66e7950900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff86161561144d57600980547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff88161790555b7f000000000000000000000000000000000000000000000000000000000000000083108061149a57507f000000000000000000000000000000000000000000000000000000000000000083115b156114d1576040517f81b64e1a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000082108061151e57507f000000000000000000000000000000000000000000000000000000000000000082115b15611555576040517f65122d7900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b81831061158e576040517f81b64e1a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000008510806115db57507f000000000000000000000000000000000000000000000000000000000000000085115b15611612576040517ff0b096ca00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000084108061165f57507f000000000000000000000000000000000000000000000000000000000000000084115b15611696576040517f8470281a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6008805473ffffffffffffffffffffffffffffffffffffffff808b167fffffffffffffffffffffffff00000000000000000000000000000000000000009283161790925560078054928a16929091169190911790556116f485613c1a565b6008805465ffffffffffff9290921674010000000000000000000000000000000000000000027fffffffffffff000000000000ffffffffffffffffffffffffffffffffffffffff90921691909117905561174d84613c1a565b6008805465ffffffffffff929092167a0100000000000000000000000000000000000000000000000000000279ffffffffffffffffffffffffffffffffffffffffffffffffffff9092169190911790556117a683613c60565b6007805461ffff9290921674010000000000000000000000000000000000000000027fffffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffff9092169190911790556117fb82613c60565b6007805461ffff92909216760100000000000000000000000000000000000000000000027fffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffffffff83168117909155604080517f95d89b4100000000000000000000000000000000000000000000000000000000815290516119759373ffffffffffffffffffffffffffffffffffffffff938416931692909217916395d89b41916004808201926000929091908290030181865afa1580156118be573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820160405261190491908101906150ba565b6040516020016119149190615128565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152828201909152600182527f3100000000000000000000000000000000000000000000000000000000000000602083015290613c9e565b61197e88613d6d565b80156119e157600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527fbe9b076dc5b65990cca9dd9d7366682482e7817a6f6bc7f4faf4dc32af497f329060200160405180910390a15b5050505050505050565b60006005544614611a6757611a62600254600354604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60208201529081019290925260608201524660808201523060a082015260009060c00160405160208183030381529060405280519060200120905090565b905090565b5060045490565b73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000163003611add576040517f43d22ee900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16611b527f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff1614611b9f576040517fe74d90a000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611ba881613e26565b611bc381604051806020016040528060008152506000613fda565b50565b60005462010000900473ffffffffffffffffffffffffffffffffffffffff163314611c1d576040517fd238ed5900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff8381169182179092556000805460405192936201000090910416917f4f2638f5949b9614ef8d5e268cb51348ad7f434a34812bf64b6e95014fbd357e9190a350565b6000611ca884338585614132565b949350505050565b73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000163003611d1f576040517f43d22ee900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16611d947f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff1614611de1576040517fe74d90a000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611dea82613e26565b611df682826001613fda565b5050565b60003073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614611e6b576040517f575bc92e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b507f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc90565b600080611f0e8a8a8080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808e0282810182019093528d82529093508d92508c918291850190849080828437600092019190915250611f0792508a91508b9050615169565b8787612ccb565b90506005611f1b82612098565b6008811115611f2c57611f2c614bf9565b14611f6b576040517f346e683e000000000000000000000000000000000000000000000000000000008152600481018290526024015b60405180910390fd5b6000818152600a60205260409081902060010180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff167401000000000000000000000000000000000000000017905560085490517f60e69a7b00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff909116906360e69a7b903490612020908e908e908e908e908e908e908e908e9060040161526f565b6000604051808303818588803b15801561203957600080fd5b505af115801561204d573d6000803e3d6000fd5b50505050507f7b1bcf1ccf901a11589afff5504d59fd0a53780eed2a952adade0348985139e08160405161208391815260200190565b60405180910390a19998505050505050505050565b6000818152600a60209081526040808320815161018081018352815473ffffffffffffffffffffffffffffffffffffffff8116825263ffffffff74010000000000000000000000000000000000000000808304821696840196909652780100000000000000000000000000000000000000000000000082048116948301949094527c010000000000000000000000000000000000000000000000000000000090048316606082015260019091015480831660808301526401000000008104831660a08301819052680100000000000000008204841660c08401526c010000000000000000000000008204841660e0840152700100000000000000000000000000000000820490931661010083015260ff938104841615156101208301527501000000000000000000000000000000000000000000810484161515610140830152760100000000000000000000000000000000000000000000900490921615156101608301528203612235576040517f219f66a000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b806101200151156122495750600792915050565b8061014001511561225d5750600292915050565b806101600151156122715750600892915050565b8060a0015163ffffffff1642101561228c5750600092915050565b8060c0015163ffffffff164210156122a75750600192915050565b806040015163ffffffff16816060015163ffffffff161115806122de575080610100015163ffffffff16816060015163ffffffff16105b156122ec5750600392915050565b6008546040517f4d0030700000000000000000000000000000000000000000000000000000000081526004810185905273ffffffffffffffffffffffffffffffffffffffff90911690634d00307090602401602060405180830381865afa15801561235b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061237f9190615072565b60000361238f5750600492915050565b6008546040517f6db2feb20000000000000000000000000000000000000000000000000000000081526004810185905273ffffffffffffffffffffffffffffffffffffffff90911690636db2feb290602401602060405180830381865afa1580156123fe573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124229190615356565b156124305750600692915050565b50600592915050565b60005462010000900473ffffffffffffffffffffffffffffffffffffffff163314612490576040517fd238ed5900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000008110806124dd57507f000000000000000000000000000000000000000000000000000000000000000081115b15612514576040517ff0b096ca00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600854604080517401000000000000000000000000000000000000000090920465ffffffffffff168252602082018390527f16569b50c8812bb18e4b5c46b0fee4a9acbb3a9dca1e1badce427e8d75b5652d910160405180910390a16008805465ffffffffffff90921674010000000000000000000000000000000000000000027fffffffffffff000000000000ffffffffffffffffffffffffffffffffffffffff909216919091179055565b60006125de83338460405180602001604052806000815250614132565b9392505050565b60015473ffffffffffffffffffffffffffffffffffffffff163314612636576040517f065cd53100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000805460405133926201000090920473ffffffffffffffffffffffffffffffffffffffff16917f8292fce18fa69edf4db7b94ea2e58241df0ae57f97e0a6c9b29067028bf92d7691a360018054600080547fffffffffffffffffffff0000000000000000000000000000000000000000ffff1673ffffffffffffffffffffffffffffffffffffffff831662010000021790557fffffffffffffffffffffffff0000000000000000000000000000000000000000169055565b600060046126fc83612098565b600881111561270d5761270d614bf9565b14612744576040517f766dfe2800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6008546040517f7c10dea60000000000000000000000000000000000000000000000000000000081526004810184905273ffffffffffffffffffffffffffffffffffffffff90911690637c10dea6906024016020604051808303816000875af11580156127b5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127d99190615072565b60408051848152602081018390529192507f65431b33ae1566469324739cd3024c5e8d7422fa2c54e71fda14b92fd5e8f1ea910160405180910390a1919050565b600080612825612d07565b905061282f612d07565b61283c336001420361359a565b11612873576040517fe33f2b3e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b855160008190036128b0576040517ffa9039ee00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b855181146128ea576040517ff9647ae200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b84518114612924576040517ff9647ae200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b83516020850120600061293a8989898533612ccb565b6000818152600a60205260409020600181015491925090640100000000900463ffffffff1615612999576040517f60a0c04300000000000000000000000000000000000000000000000000000000815260048101839052602401611f62565b60085474010000000000000000000000000000000000000000810465ffffffffffff9081164201917a01000000000000000000000000000000000000000000000000000090041681016129eb8261442a565b8360010160046101000a81548163ffffffff021916908363ffffffff160217905550612a168161442a565b8360010160086101000a81548163ffffffff021916908363ffffffff160217905550612a418761442a565b83600101600c6101000a81548163ffffffff021916908363ffffffff160217905550612a73612a6e610eee565b61442a565b60018401805463ffffffff92909216700100000000000000000000000000000000027fffffffffffffffffffffffff00000000ffffffffffffffffffffffffffffffff90921691909117905582547fffffffffffffffffffffffff00000000000000000000000000000000000000001633178355612af04261442a565b835463ffffffff9190911674010000000000000000000000000000000000000000027fffffffffffffffff00000000ffffffffffffffffffffffffffffffffffffffff9091161783556040517f032b260f9afa08d3ff613d6248a8dce651b8c583a050ca2f9c666a179617b15890612b759086908f908f908f908f908c908b90615441565b60405180910390a150919a9950505050505050505050565b60005462010000900473ffffffffffffffffffffffffffffffffffffffff163314612be4576040517fd238ed5900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8116612c31576040517f66e7950900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6009546040805173ffffffffffffffffffffffffffffffffffffffff928316815291831660208301527e36bea9286cc431052f56dee1918d8a6665ef6f6370e6b4d71b7deaac1d0556910160405180910390a1600980547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b60008585858585604051602001612ce69594939291906155c6565b60405160208183030381529060405280519060200120905095945050505050565b600754604080517f18160ddd00000000000000000000000000000000000000000000000000000000815290516000927f00000000000000000000000000000000000000000000000000000000000000009261ffff740100000000000000000000000000000000000000008304169273ffffffffffffffffffffffffffffffffffffffff909216916318160ddd916004808201926020929091908290030181865afa158015610fa2573d6000803e3d6000fd5b600084421115612df5576040517f6ed6bef000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000612dff6119eb565b73ffffffffffffffffffffffffffffffffffffffff8a1660008181526006602090815260409182902080546001810190915582517f00000000000000000000000000000000000000000000000000000000000000008184015280840194909452606084018d9052608084018c905260a084015260c08084018b90528251808503909101815260e0840190925281519101207f190100000000000000000000000000000000000000000000000000000000000061010083015261010282019290925261012281019190915261014201604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181528282528051602091820120600080855291840180845281905260ff89169284019290925260608301879052608083018690529092509060019060a0016020604051602081039080840390855afa158015612f56573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015191505073ffffffffffffffffffffffffffffffffffffffff81161580612fd057508973ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614155b15613007576040517fa3402a3800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b613022898b8a60405180602001604052806000815250614132565b9a9950505050505050505050565b600761303b82612098565b600881111561304c5761304c614bf9565b03613083576040517f44f967fa00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000818152600a6020908152604091829020825161018081018452815473ffffffffffffffffffffffffffffffffffffffff811680835263ffffffff74010000000000000000000000000000000000000000808404821696850196909652780100000000000000000000000000000000000000000000000083048116968401969096527c01000000000000000000000000000000000000000000000000000000009091048516606083015260019092015480851660808301526401000000008104851660a0830152680100000000000000008104851660c08301526c010000000000000000000000008104851660e0830152700100000000000000000000000000000000810490941661010082015260ff9284048316151561012082015275010000000000000000000000000000000000000000008404831615156101408201527601000000000000000000000000000000000000000000009093049091161515610160830152331480159061321357508060e0015163ffffffff1661321082600001516001420361359a565b10155b1561324a576040517f7d78031200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000828152600a60205260409081902060010180547fffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff16750100000000000000000000000000000000000000000017905560085490517f0dc051f80000000000000000000000000000000000000000000000000000000081526004810184905273ffffffffffffffffffffffffffffffffffffffff90911690630dc051f890602401602060405180830381865afa158015613309573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061332d9190615356565b156133b7576008546040517fc4d252f50000000000000000000000000000000000000000000000000000000081526004810184905273ffffffffffffffffffffffffffffffffffffffff9091169063c4d252f590602401600060405180830381600087803b15801561339e57600080fd5b505af11580156133b2573d6000803e3d6000fd5b505050505b6040518281527f88ae8321c96cee88d802409f3677f889d8a6743c4631b069fe600a3a9b07e020906020015b60405180910390a15050565b60005462010000900473ffffffffffffffffffffffffffffffffffffffff163314613446576040517fd238ed5900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000081108061349357507f000000000000000000000000000000000000000000000000000000000000000081115b806134be5750600754760100000000000000000000000000000000000000000000900461ffff168110155b156134f5576040517f81b64e1a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600754604080517401000000000000000000000000000000000000000090920461ffff168252602082018390527f3597f3d5106fd545a99b5a9cd1e0e7a985f0477ec13aa8c739119325d747fb35910160405180910390a16007805461ffff90921674010000000000000000000000000000000000000000027fffffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffff909216919091179055565b6007546040517f3a46b1a800000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8481166004830152602482018490526000921690633a46b1a890604401602060405180830381865afa158015613612573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125de9190615072565b60005462010000900473ffffffffffffffffffffffffffffffffffffffff16331461368d576040517fd238ed5900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000008110806136da57507f000000000000000000000000000000000000000000000000000000000000000081115b80613703575060075474010000000000000000000000000000000000000000900461ffff168111155b1561373a576040517f65122d7900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6007546040805176010000000000000000000000000000000000000000000090920461ffff168252602082018390527fcefdafdfb2f62f73b0ac8d13e7f3cd4d2dbd9eecd15571b7ac644d97fa9083b1910160405180910390a16007805461ffff909216760100000000000000000000000000000000000000000000027fffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffffffff909216919091179055565b60005462010000900473ffffffffffffffffffffffffffffffffffffffff16331461383a576040517fd238ed5900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000081108061388757507f000000000000000000000000000000000000000000000000000000000000000081115b156138be576040517f8470281a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600854604080517a01000000000000000000000000000000000000000000000000000090920465ffffffffffff168252602082018390527fffc708f072ca56e3d45ef0cb288b96cb9378f5f63e1646868bfbc9c38f4263a1910160405180910390a16008805465ffffffffffff9092167a0100000000000000000000000000000000000000000000000000000279ffffffffffffffffffffffffffffffffffffffffffffffffffff909216919091179055565b60005462010000900473ffffffffffffffffffffffffffffffffffffffff1633146139c8576040517fd238ed5900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611bc38161446a565b60095473ffffffffffffffffffffffffffffffffffffffff163314613a22576040517f16e025ec00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6007613a2d82612098565b6008811115613a3e57613a3e614bf9565b03613a75576040517f44f967fa00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000818152600a6020526040908190206001810180547fffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffff1676010000000000000000000000000000000000000000000017905560085491517f0dc051f800000000000000000000000000000000000000000000000000000000815260048101849052909173ffffffffffffffffffffffffffffffffffffffff1690630dc051f890602401602060405180830381865afa158015613b36573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613b5a9190615356565b15613be4576008546040517fc4d252f50000000000000000000000000000000000000000000000000000000081526004810184905273ffffffffffffffffffffffffffffffffffffffff9091169063c4d252f590602401600060405180830381600087803b158015613bcb57600080fd5b505af1158015613bdf573d6000803e3d6000fd5b505050505b6040518281527f0c8bf601915d1f39ef591226bc69b3becc23fcb3616673c419062aa44beb42da906020016133e3565b3b151590565b600065ffffffffffff821115613c5c576040517fb0a90f3300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5090565b600061ffff821115613c5c576040517fb0a90f3300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600054610100900460ff16613cdf576040517f624bb4ce00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b815160208084019190912060025581519082012060035546600555613d66600254600354604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60208201529081019290925260608201524660808201523060a082015260009060c00160405160208183030381529060405280519060200120905090565b6004555050565b600054610100900460ff16613dae576040517f624bb4ce00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080547fffffffffffffffffffff0000000000000000000000000000000000000000ffff166201000073ffffffffffffffffffffffffffffffffffffffff84169081029190911782556040519091907f8292fce18fa69edf4db7b94ea2e58241df0ae57f97e0a6c9b29067028bf92d76908290a350565b60005462010000900473ffffffffffffffffffffffffffffffffffffffff163314613e7d576040517fd238ed5900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16639bb8dcfd613ef77f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5473ffffffffffffffffffffffffffffffffffffffff1690565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b16815273ffffffffffffffffffffffffffffffffffffffff91821660048201529084166024820152604401602060405180830381865afa158015613f68573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613f8c9190615356565b611bc3576040517fc40d973400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff82166004820152602401611f62565b7f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd91435460ff16156140125761400d83614536565b505050565b8273ffffffffffffffffffffffffffffffffffffffff166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa925050508015614097575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820190925261409491810190615072565b60015b6140cd576040517fc0bb20b200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc8114614126576040517f0849b49600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5061400d8383836145ec565b6000600161413f86612098565b600881111561415057614150614bf9565b14614187576040517f8a59eceb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000858152600b6020908152604080832073ffffffffffffffffffffffffffffffffffffffff8816845290915290205460ff16156141f1576040517feb20971100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600283111561422c576040517f3485325a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000858152600b6020908152604080832073ffffffffffffffffffffffffffffffffffffffff88168452825280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055878352600a909152812080549091906142bd90879063ffffffff740100000000000000000000000000000000000000009091041661359a565b905084600003614329576142d08161442a565b825463ffffffff78010000000000000000000000000000000000000000000000008083048216909301169091027fffffffff00000000ffffffffffffffffffffffffffffffffffffffffffffffff9091161782556143e1565b846001036143935761433a8161442a565b825463ffffffff7c01000000000000000000000000000000000000000000000000000000008083048216909301169091027bffffffffffffffffffffffffffffffffffffffffffffffffffffffff9091161782556143e1565b846002036143e1576143a48161442a565b6001830180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000811663ffffffff91821693909301169190911790555b7f0c165c85edbf8f9b99d51793c9429beb9dc2b608a7f81e64623052f829657af3868887848860405161441895949392919061562e565b60405180910390a19695505050505050565b600063ffffffff821115613c5c576040517fb0a90f3300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000805460405173ffffffffffffffffffffffffffffffffffffffff808516936201000090930416917f8292fce18fa69edf4db7b94ea2e58241df0ae57f97e0a6c9b29067028bf92d7691a36000805473ffffffffffffffffffffffffffffffffffffffff80841662010000027fffffffffffffffffffff0000000000000000000000000000000000000000ffff909216919091179091556001541615611bc357600180547fffffffffffffffffffffffff000000000000000000000000000000000000000016905550565b803b614586576040517fc40d973400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff82166004820152602401611f62565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b6145f583614617565b6000825111806146025750805b1561400d57614611838361466c565b50505050565b61462081614536565b60405173ffffffffffffffffffffffffffffffffffffffff821681527fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b9060200160405180910390a150565b6060823b6146a6576040517f37f2022900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000808473ffffffffffffffffffffffffffffffffffffffff16846040516146ce919061567a565b600060405180830381855af49150503d8060008114614709576040519150601f19603f3d011682016040523d82523d6000602084013e61470e565b606091505b509150915061471d8282614726565b95945050505050565b6060821561473557508061106e565b8151156147455781518083602001fd5b6040517f62536b1000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006020828403121561478957600080fd5b5035919050565b803573ffffffffffffffffffffffffffffffffffffffff811681146147b457600080fd5b919050565b600080600080600080600060e0888a0312156147d457600080fd5b6147dd88614790565b96506147eb60208901614790565b95506147f960408901614790565b969995985095966060810135965060808101359560a0820135955060c0909101359350915050565b60006020828403121561483357600080fd5b6125de82614790565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff811182821017156148b2576148b261483c565b604052919050565b600067ffffffffffffffff8211156148d4576148d461483c565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b600082601f83011261491157600080fd5b813561492461491f826148ba565b61486b565b81815284602083860101111561493957600080fd5b816020850160208301376000918101602001919091529392505050565b60008060006060848603121561496b57600080fd5b8335925060208401359150604084013567ffffffffffffffff81111561499057600080fd5b61499c86828701614900565b9150509250925092565b815173ffffffffffffffffffffffffffffffffffffffff168152610180810160208301516149dc602084018263ffffffff169052565b5060408301516149f4604084018263ffffffff169052565b506060830151614a0c606084018263ffffffff169052565b506080830151614a24608084018263ffffffff169052565b5060a0830151614a3c60a084018263ffffffff169052565b5060c0830151614a5460c084018263ffffffff169052565b5060e0830151614a6c60e084018263ffffffff169052565b506101008381015163ffffffff16908301526101208084015115159083015261014080840151151590830152610160928301511515929091019190915290565b60008060408385031215614abf57600080fd5b614ac883614790565b9150602083013567ffffffffffffffff811115614ae457600080fd5b614af085828601614900565b9150509250929050565b60008083601f840112614b0c57600080fd5b50813567ffffffffffffffff811115614b2457600080fd5b6020830191508360208260051b8501011115614b3f57600080fd5b9250929050565b60008060008060008060008060a0898b031215614b6257600080fd5b883567ffffffffffffffff80821115614b7a57600080fd5b614b868c838d01614afa565b909a50985060208b0135915080821115614b9f57600080fd5b614bab8c838d01614afa565b909850965060408b0135915080821115614bc457600080fd5b50614bd18b828c01614afa565b90955093505060608901359150614bea60808a01614790565b90509295985092959890939650565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b6020810160098310614c63577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b91905290565b60008060408385031215614c7c57600080fd5b50508035926020909101359150565b600067ffffffffffffffff821115614ca557614ca561483c565b5060051b60200190565b600082601f830112614cc057600080fd5b81356020614cd061491f83614c8b565b82815260059290921b84018101918181019086841115614cef57600080fd5b8286015b84811015614d1157614d0481614790565b8352918301918301614cf3565b509695505050505050565b600082601f830112614d2d57600080fd5b81356020614d3d61491f83614c8b565b82815260059290921b84018101918181019086841115614d5c57600080fd5b8286015b84811015614d115780358352918301918301614d60565b6000614d8561491f84614c8b565b8381529050602080820190600585901b840186811115614da457600080fd5b845b81811015614de057803567ffffffffffffffff811115614dc65760008081fd5b614dd289828901614900565b855250928201928201614da6565b505050509392505050565b600082601f830112614dfc57600080fd5b6125de83833560208501614d77565b60008060008060808587031215614e2157600080fd5b843567ffffffffffffffff80821115614e3957600080fd5b614e4588838901614caf565b95506020870135915080821115614e5b57600080fd5b614e6788838901614d1c565b94506040870135915080821115614e7d57600080fd5b614e8988838901614deb565b93506060870135915080821115614e9f57600080fd5b50614eac87828801614900565b91505092959194509250565b60005b83811015614ed3578181015183820152602001614ebb565b50506000910152565b60008151808452614ef4816020860160208601614eb8565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6020815260006125de6020830184614edc565b600080600080600060a08688031215614f5157600080fd5b853567ffffffffffffffff80821115614f6957600080fd5b614f7589838a01614caf565b96506020880135915080821115614f8b57600080fd5b614f9789838a01614d1c565b95506040880135915080821115614fad57600080fd5b50614fba88828901614deb565b93505060608601359150614fd060808701614790565b90509295509295909350565b600080600080600080600060e0888a031215614ff757600080fd5b61500088614790565b9650602088013595506040880135945060608801359350608088013560ff8116811461502b57600080fd5b9699959850939692959460a0840135945060c09093013592915050565b6000806040838503121561505b57600080fd5b61506483614790565b946020939093013593505050565b60006020828403121561508457600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b6000602082840312156150cc57600080fd5b815167ffffffffffffffff8111156150e357600080fd5b8201601f810184136150f457600080fd5b805161510261491f826148ba565b81815285602083850101111561511757600080fd5b61471d826020830160208601614eb8565b6000825161513a818460208701614eb8565b7f20474f5600000000000000000000000000000000000000000000000000000000920191825250600401919050565b60006125de368484614d77565b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b81835260006020808501808196508560051b810191508460005b8781101561526257828403895281357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe188360301811261521857600080fd5b8701858101903567ffffffffffffffff81111561523457600080fd5b80360382131561524357600080fd5b61524e868284615176565b9a87019a95505050908401906001016151d9565b5091979650505050505050565b60a0808252810188905260008960c08301825b8b8110156152bd5773ffffffffffffffffffffffffffffffffffffffff6152a884614790565b16825260209283019290910190600101615282565b5083810360208501528881527f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8911156152f657600080fd5b8860051b9150818a6020830137018281036020908101604085015261531e90820187896151bf565b915050836060830152615349608083018473ffffffffffffffffffffffffffffffffffffffff169052565b9998505050505050505050565b60006020828403121561536857600080fd5b815180151581146125de57600080fd5b600081518084526020808501945080840160005b838110156153be57815173ffffffffffffffffffffffffffffffffffffffff168752958201959082019060010161538c565b509495945050505050565b600081518084526020808501945080840160005b838110156153be578151875295820195908201906001016153dd565b600081518084526020808501808196508360051b8101915082860160005b8581101561526257828403895261542f848351614edc565b98850198935090840190600101615417565b600061024089835280602084015261545b8184018a615378565b9050828103604084015261546f81896153c9565b9050828103606084015261548381886153f9565b905082810360808401526154978187614edc565b9150508360a083015282546154da60c0840173ffffffffffffffffffffffffffffffffffffffff831673ffffffffffffffffffffffffffffffffffffffff169052565b63ffffffff60a082901c811660e085015260c082901c811661010085015260e082901c610120850152600185015463ffffffff8282161661014086015291506155316101608501828460201c1663ffffffff169052565b6155496101808501828460401c1663ffffffff169052565b6155616101a08501828460601c1663ffffffff169052565b6155796101c08501828460801c1663ffffffff169052565b5061558f6101e0840160ff8360a01c1615159052565b6155a4610200840160ff8360a81c1615159052565b6155b9610220840160ff8360b01c1615159052565b5098975050505050505050565b60a0815260006155d960a0830188615378565b82810360208401526155eb81886153c9565b905082810360408401526155ff81876153f9565b91505083606083015273ffffffffffffffffffffffffffffffffffffffff831660808301529695505050505050565b73ffffffffffffffffffffffffffffffffffffffff8616815284602082015283604082015282606082015260a06080820152600061566f60a0830184614edc565b979650505050505050565b6000825161568c818460208701614eb8565b919091019291505056fea264697066735822122064b51134927b2d8ab75f42bea6c26a1cad09ae79e3446254c7140cc4d5077ab764736f6c634300081000330000000000000000000000000e9f3382cf2508e3bc83248b5b4707fba86d7ee0
Deployed Bytecode
0x60806040526004361061034a5760003560e01c806379ba5097116101bb578063c82fbd08116100f7578063eb9019d411610095578063f2fde38b1161006f578063f2fde38b14610e4f578063f990b49114610e6f578063fb6f93f914610ea3578063fc0c546a14610ec357600080fd5b8063eb9019d414610def578063ebfdeacf14610e0f578063ef00ef4314610e2f57600080fd5b8063d8bff440116100d1578063d8bff44014610d45578063e30c397814610d70578063e42eb4f614610d9b578063e48083fe14610dbb57600080fd5b8063c82fbd0814610b30578063cbcda20114610b64578063d14b85b914610ba257600080fd5b8063a0a8e46011610164578063b11262631161013e578063b112626314610aa7578063b58131b014610adb578063c3e5178914610af0578063c4d252f514610b1057600080fd5b8063a0a8e46014610a07578063a64e024a14610a53578063aedbfe3314610a8757600080fd5b8063865229731161019557806386522973146109825780638da5cb5b146109b65780639dcbfd7d146109e757600080fd5b806379ba50971461092d5780637c10dea6146109425780637d5e81e21461096257600080fd5b80633bec7f5b1161028a57806352d1902d1161023357806361d585da1161020d57806361d585da1461087d57806363d61a19146108aa57806370ae92d2146108ca57806375a12d721461090d57600080fd5b806352d1902d1461080957806360e69a7b1461081e57806361d027b31461083157600080fd5b8063430694cf11610264578063430694cf146105d557806348b1aeb4146107c55780634f1ef286146107f657600080fd5b80633bec7f5b146105405780633d24375f1461057357806341f9b62c146105b557600080fd5b8063215809ca116102f75780633644e515116102d15780633644e515146104b65780633659cfe6146104cb5780633932abb1146104eb578063395db2cd1461052057600080fd5b8063215809ca1461044d57806323452b9c146104815780632b4656c81461049657600080fd5b8063177e5a9f11610328578063177e5a9f146103e25780631e5cc3bd146104025780631e7b5d3a1461041957600080fd5b806302a251a31461034f578063032bbc53146103995780631703a018146103cd575b600080fd5b34801561035b57600080fd5b506008547a010000000000000000000000000000000000000000000000000000900465ffffffffffff165b6040519081526020015b60405180910390f35b3480156103a557600080fd5b506103867f00000000000000000000000000000000000000000000000000000000000000c881565b3480156103d957600080fd5b50610386610eee565b3480156103ee57600080fd5b506103866103fd366004614777565b610fda565b34801561040e57600080fd5b50610417611074565b005b34801561042557600080fd5b506103867f00000000000000000000000000000000000000000000000000000000000003e881565b34801561045957600080fd5b506103867f000000000000000000000000000000000000000000000000000000000000025881565b34801561048d57600080fd5b50610417611147565b3480156104a257600080fd5b506104176104b13660046147b9565b611219565b3480156104c257600080fd5b506103866119eb565b3480156104d757600080fd5b506104176104e6366004614821565b611a6e565b3480156104f757600080fd5b5060085474010000000000000000000000000000000000000000900465ffffffffffff16610386565b34801561052c57600080fd5b5061041761053b366004614821565b611bc6565b34801561054c57600080fd5b50600754760100000000000000000000000000000000000000000000900461ffff16610386565b34801561057f57600080fd5b5061038661058e366004614777565b6000908152600a602052604090206001015468010000000000000000900463ffffffff1690565b3480156105c157600080fd5b506103866105d0366004614956565b611c9a565b3480156105e157600080fd5b506107b86105f0366004614777565b6040805161018081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e08101829052610100810182905261012081018290526101408101829052610160810191909152506000908152600a6020908152604091829020825161018081018452815473ffffffffffffffffffffffffffffffffffffffff8116825263ffffffff74010000000000000000000000000000000000000000808304821695840195909552780100000000000000000000000000000000000000000000000082048116958301959095527c010000000000000000000000000000000000000000000000000000000090048416606082015260019091015480841660808301526401000000008104841660a0830152680100000000000000008104841660c08301526c010000000000000000000000008104841660e0830152700100000000000000000000000000000000810490931661010082015260ff91830482161515610120820152750100000000000000000000000000000000000000000083048216151561014082015276010000000000000000000000000000000000000000000090920416151561016082015290565b60405161039091906149a6565b3480156107d157600080fd5b5060075474010000000000000000000000000000000000000000900461ffff16610386565b610417610804366004614aac565b611cb0565b34801561081557600080fd5b50610386611dfa565b61038661082c366004614b46565b611e90565b34801561083d57600080fd5b5060085473ffffffffffffffffffffffffffffffffffffffff165b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610390565b34801561088957600080fd5b5061089d610898366004614777565b612098565b6040516103909190614c28565b3480156108b657600080fd5b506104176108c5366004614777565b612439565b3480156108d657600080fd5b506103866108e5366004614821565b73ffffffffffffffffffffffffffffffffffffffff1660009081526006602052604090205490565b34801561091957600080fd5b50610386610928366004614c69565b6125c1565b34801561093957600080fd5b506104176125e5565b34801561094e57600080fd5b5061038661095d366004614777565b6126ef565b34801561096e57600080fd5b5061038661097d366004614e0b565b61281a565b34801561098e57600080fd5b506103867f4b87515bde17bd1a40e570a7c028fa4b7e66dd1ed9dc7c0cd8fd78d67ca34f2881565b3480156109c257600080fd5b5060005462010000900473ffffffffffffffffffffffffffffffffffffffff16610858565b3480156109f357600080fd5b50610417610a02366004614821565b612b8d565b348015610a1357600080fd5b50604080518082018252600581527f312e322e30000000000000000000000000000000000000000000000000000000602082015290516103909190614f26565b348015610a5f57600080fd5b506103867f0000000000000000000000000000000000000000000000000000000000dd7c0081565b348015610a9357600080fd5b50610386610aa2366004614f39565b612ccb565b348015610ab357600080fd5b506103867f0000000000000000000000000000000000000000000000000000000000dd7c0081565b348015610ae757600080fd5b50610386612d07565b348015610afc57600080fd5b50610386610b0b366004614fdc565b612db9565b348015610b1c57600080fd5b50610417610b2b366004614777565b613030565b348015610b3c57600080fd5b506103867f000000000000000000000000000000000000000000000000000000000000000181565b348015610b7057600080fd5b50610386610b7f366004614777565b6000908152600a6020526040902060010154640100000000900463ffffffff1690565b348015610bae57600080fd5b50610d2a610bbd366004614777565b6000908152600a6020908152604091829020825161018081018452815473ffffffffffffffffffffffffffffffffffffffff8116825263ffffffff740100000000000000000000000000000000000000008083048216958401959095527801000000000000000000000000000000000000000000000000820481169583018690527c0100000000000000000000000000000000000000000000000000000000909104811660608301819052600190930154808216608084018190526401000000008204831660a0850152680100000000000000008204831660c08501526c010000000000000000000000008204831660e0850152700100000000000000000000000000000000820490921661010084015260ff94810485161515610120840152750100000000000000000000000000000000000000000081048516151561014084015276010000000000000000000000000000000000000000000090049093161515610160909101529192565b60408051938452602084019290925290820152606001610390565b348015610d5157600080fd5b5060095473ffffffffffffffffffffffffffffffffffffffff16610858565b348015610d7c57600080fd5b5060015473ffffffffffffffffffffffffffffffffffffffff16610858565b348015610da757600080fd5b50610417610db6366004614777565b6133ef565b348015610dc757600080fd5b506103867f000000000000000000000000000000000000000000000000000000000000000181565b348015610dfb57600080fd5b50610386610e0a366004615048565b61359a565b348015610e1b57600080fd5b50610417610e2a366004614777565b613636565b348015610e3b57600080fd5b50610417610e4a366004614777565b6137e3565b348015610e5b57600080fd5b50610417610e6a366004614821565b613971565b348015610e7b57600080fd5b506103867f00000000000000000000000000000000000000000000000000000000000007d081565b348015610eaf57600080fd5b50610417610ebe366004614777565b6139d1565b348015610ecf57600080fd5b5060075473ffffffffffffffffffffffffffffffffffffffff16610858565b600754604080517f18160ddd00000000000000000000000000000000000000000000000000000000815290516000927f00000000000000000000000000000000000000000000000000000000000027109261ffff7601000000000000000000000000000000000000000000008304169273ffffffffffffffffffffffffffffffffffffffff909216916318160ddd916004808201926020929091908290030181865afa158015610fa2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fc69190615072565b0281610fd457610fd461508b565b04905090565b6008546040517f4d0030700000000000000000000000000000000000000000000000000000000081526004810183905260009173ffffffffffffffffffffffffffffffffffffffff1690634d00307090602401602060405180830381865afa15801561104a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061106e9190615072565b92915050565b60005462010000900473ffffffffffffffffffffffffffffffffffffffff1633146110cb576040517fd238ed5900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6009546040805173ffffffffffffffffffffffffffffffffffffffff9092168252600060208301527e36bea9286cc431052f56dee1918d8a6665ef6f6370e6b4d71b7deaac1d0556910160405180910390a1600980547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055565b60005462010000900473ffffffffffffffffffffffffffffffffffffffff16331461119e576040517fd238ed5900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001546000805460405173ffffffffffffffffffffffffffffffffffffffff9384169362010000909204909116917f682679deecef4dcd49674845cc1e3a075fea9073680aa445a8207d5a4bdea3da91a3600180547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055565b600054610100900460ff1615801580611236575060005460ff1615155b80156112525750303b151580611252575060005460ff16600114155b15611289576040517f439a74c900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905580156112e757600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b3373ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000e9f3382cf2508e3bc83248b5b4707fba86d7ee01614611356576040517fa2ddd97100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff88166113a3576040517f66e7950900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff87166113f0576040517f66e7950900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff86161561144d57600980547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff88161790555b7f000000000000000000000000000000000000000000000000000000000000000183108061149a57507f00000000000000000000000000000000000000000000000000000000000003e883115b156114d1576040517f81b64e1a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000c882108061151e57507f00000000000000000000000000000000000000000000000000000000000007d082115b15611555576040517f65122d7900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b81831061158e576040517f81b64e1a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000018510806115db57507f0000000000000000000000000000000000000000000000000000000000dd7c0085115b15611612576040517ff0b096ca00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000025884108061165f57507f0000000000000000000000000000000000000000000000000000000000dd7c0084115b15611696576040517f8470281a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6008805473ffffffffffffffffffffffffffffffffffffffff808b167fffffffffffffffffffffffff00000000000000000000000000000000000000009283161790925560078054928a16929091169190911790556116f485613c1a565b6008805465ffffffffffff9290921674010000000000000000000000000000000000000000027fffffffffffff000000000000ffffffffffffffffffffffffffffffffffffffff90921691909117905561174d84613c1a565b6008805465ffffffffffff929092167a0100000000000000000000000000000000000000000000000000000279ffffffffffffffffffffffffffffffffffffffffffffffffffff9092169190911790556117a683613c60565b6007805461ffff9290921674010000000000000000000000000000000000000000027fffffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffff9092169190911790556117fb82613c60565b6007805461ffff92909216760100000000000000000000000000000000000000000000027fffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffffffff83168117909155604080517f95d89b4100000000000000000000000000000000000000000000000000000000815290516119759373ffffffffffffffffffffffffffffffffffffffff938416931692909217916395d89b41916004808201926000929091908290030181865afa1580156118be573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820160405261190491908101906150ba565b6040516020016119149190615128565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152828201909152600182527f3100000000000000000000000000000000000000000000000000000000000000602083015290613c9e565b61197e88613d6d565b80156119e157600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527fbe9b076dc5b65990cca9dd9d7366682482e7817a6f6bc7f4faf4dc32af497f329060200160405180910390a15b5050505050505050565b60006005544614611a6757611a62600254600354604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60208201529081019290925260608201524660808201523060a082015260009060c00160405160208183030381529060405280519060200120905090565b905090565b5060045490565b73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000006763c3210bdc1d9a1f917706a16f259913198376163003611add576040517f43d22ee900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f0000000000000000000000006763c3210bdc1d9a1f917706a16f25991319837673ffffffffffffffffffffffffffffffffffffffff16611b527f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff1614611b9f576040517fe74d90a000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611ba881613e26565b611bc381604051806020016040528060008152506000613fda565b50565b60005462010000900473ffffffffffffffffffffffffffffffffffffffff163314611c1d576040517fd238ed5900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff8381169182179092556000805460405192936201000090910416917f4f2638f5949b9614ef8d5e268cb51348ad7f434a34812bf64b6e95014fbd357e9190a350565b6000611ca884338585614132565b949350505050565b73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000006763c3210bdc1d9a1f917706a16f259913198376163003611d1f576040517f43d22ee900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f0000000000000000000000006763c3210bdc1d9a1f917706a16f25991319837673ffffffffffffffffffffffffffffffffffffffff16611d947f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff1614611de1576040517fe74d90a000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611dea82613e26565b611df682826001613fda565b5050565b60003073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000006763c3210bdc1d9a1f917706a16f2599131983761614611e6b576040517f575bc92e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b507f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc90565b600080611f0e8a8a8080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808e0282810182019093528d82529093508d92508c918291850190849080828437600092019190915250611f0792508a91508b9050615169565b8787612ccb565b90506005611f1b82612098565b6008811115611f2c57611f2c614bf9565b14611f6b576040517f346e683e000000000000000000000000000000000000000000000000000000008152600481018290526024015b60405180910390fd5b6000818152600a60205260409081902060010180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff167401000000000000000000000000000000000000000017905560085490517f60e69a7b00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff909116906360e69a7b903490612020908e908e908e908e908e908e908e908e9060040161526f565b6000604051808303818588803b15801561203957600080fd5b505af115801561204d573d6000803e3d6000fd5b50505050507f7b1bcf1ccf901a11589afff5504d59fd0a53780eed2a952adade0348985139e08160405161208391815260200190565b60405180910390a19998505050505050505050565b6000818152600a60209081526040808320815161018081018352815473ffffffffffffffffffffffffffffffffffffffff8116825263ffffffff74010000000000000000000000000000000000000000808304821696840196909652780100000000000000000000000000000000000000000000000082048116948301949094527c010000000000000000000000000000000000000000000000000000000090048316606082015260019091015480831660808301526401000000008104831660a08301819052680100000000000000008204841660c08401526c010000000000000000000000008204841660e0840152700100000000000000000000000000000000820490931661010083015260ff938104841615156101208301527501000000000000000000000000000000000000000000810484161515610140830152760100000000000000000000000000000000000000000000900490921615156101608301528203612235576040517f219f66a000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b806101200151156122495750600792915050565b8061014001511561225d5750600292915050565b806101600151156122715750600892915050565b8060a0015163ffffffff1642101561228c5750600092915050565b8060c0015163ffffffff164210156122a75750600192915050565b806040015163ffffffff16816060015163ffffffff161115806122de575080610100015163ffffffff16816060015163ffffffff16105b156122ec5750600392915050565b6008546040517f4d0030700000000000000000000000000000000000000000000000000000000081526004810185905273ffffffffffffffffffffffffffffffffffffffff90911690634d00307090602401602060405180830381865afa15801561235b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061237f9190615072565b60000361238f5750600492915050565b6008546040517f6db2feb20000000000000000000000000000000000000000000000000000000081526004810185905273ffffffffffffffffffffffffffffffffffffffff90911690636db2feb290602401602060405180830381865afa1580156123fe573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124229190615356565b156124305750600692915050565b50600592915050565b60005462010000900473ffffffffffffffffffffffffffffffffffffffff163314612490576040517fd238ed5900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000018110806124dd57507f0000000000000000000000000000000000000000000000000000000000dd7c0081115b15612514576040517ff0b096ca00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600854604080517401000000000000000000000000000000000000000090920465ffffffffffff168252602082018390527f16569b50c8812bb18e4b5c46b0fee4a9acbb3a9dca1e1badce427e8d75b5652d910160405180910390a16008805465ffffffffffff90921674010000000000000000000000000000000000000000027fffffffffffff000000000000ffffffffffffffffffffffffffffffffffffffff909216919091179055565b60006125de83338460405180602001604052806000815250614132565b9392505050565b60015473ffffffffffffffffffffffffffffffffffffffff163314612636576040517f065cd53100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000805460405133926201000090920473ffffffffffffffffffffffffffffffffffffffff16917f8292fce18fa69edf4db7b94ea2e58241df0ae57f97e0a6c9b29067028bf92d7691a360018054600080547fffffffffffffffffffff0000000000000000000000000000000000000000ffff1673ffffffffffffffffffffffffffffffffffffffff831662010000021790557fffffffffffffffffffffffff0000000000000000000000000000000000000000169055565b600060046126fc83612098565b600881111561270d5761270d614bf9565b14612744576040517f766dfe2800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6008546040517f7c10dea60000000000000000000000000000000000000000000000000000000081526004810184905273ffffffffffffffffffffffffffffffffffffffff90911690637c10dea6906024016020604051808303816000875af11580156127b5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127d99190615072565b60408051848152602081018390529192507f65431b33ae1566469324739cd3024c5e8d7422fa2c54e71fda14b92fd5e8f1ea910160405180910390a1919050565b600080612825612d07565b905061282f612d07565b61283c336001420361359a565b11612873576040517fe33f2b3e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b855160008190036128b0576040517ffa9039ee00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b855181146128ea576040517ff9647ae200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b84518114612924576040517ff9647ae200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b83516020850120600061293a8989898533612ccb565b6000818152600a60205260409020600181015491925090640100000000900463ffffffff1615612999576040517f60a0c04300000000000000000000000000000000000000000000000000000000815260048101839052602401611f62565b60085474010000000000000000000000000000000000000000810465ffffffffffff9081164201917a01000000000000000000000000000000000000000000000000000090041681016129eb8261442a565b8360010160046101000a81548163ffffffff021916908363ffffffff160217905550612a168161442a565b8360010160086101000a81548163ffffffff021916908363ffffffff160217905550612a418761442a565b83600101600c6101000a81548163ffffffff021916908363ffffffff160217905550612a73612a6e610eee565b61442a565b60018401805463ffffffff92909216700100000000000000000000000000000000027fffffffffffffffffffffffff00000000ffffffffffffffffffffffffffffffff90921691909117905582547fffffffffffffffffffffffff00000000000000000000000000000000000000001633178355612af04261442a565b835463ffffffff9190911674010000000000000000000000000000000000000000027fffffffffffffffff00000000ffffffffffffffffffffffffffffffffffffffff9091161783556040517f032b260f9afa08d3ff613d6248a8dce651b8c583a050ca2f9c666a179617b15890612b759086908f908f908f908f908c908b90615441565b60405180910390a150919a9950505050505050505050565b60005462010000900473ffffffffffffffffffffffffffffffffffffffff163314612be4576040517fd238ed5900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8116612c31576040517f66e7950900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6009546040805173ffffffffffffffffffffffffffffffffffffffff928316815291831660208301527e36bea9286cc431052f56dee1918d8a6665ef6f6370e6b4d71b7deaac1d0556910160405180910390a1600980547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b60008585858585604051602001612ce69594939291906155c6565b60405160208183030381529060405280519060200120905095945050505050565b600754604080517f18160ddd00000000000000000000000000000000000000000000000000000000815290516000927f00000000000000000000000000000000000000000000000000000000000027109261ffff740100000000000000000000000000000000000000008304169273ffffffffffffffffffffffffffffffffffffffff909216916318160ddd916004808201926020929091908290030181865afa158015610fa2573d6000803e3d6000fd5b600084421115612df5576040517f6ed6bef000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000612dff6119eb565b73ffffffffffffffffffffffffffffffffffffffff8a1660008181526006602090815260409182902080546001810190915582517f4b87515bde17bd1a40e570a7c028fa4b7e66dd1ed9dc7c0cd8fd78d67ca34f288184015280840194909452606084018d9052608084018c905260a084015260c08084018b90528251808503909101815260e0840190925281519101207f190100000000000000000000000000000000000000000000000000000000000061010083015261010282019290925261012281019190915261014201604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181528282528051602091820120600080855291840180845281905260ff89169284019290925260608301879052608083018690529092509060019060a0016020604051602081039080840390855afa158015612f56573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015191505073ffffffffffffffffffffffffffffffffffffffff81161580612fd057508973ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614155b15613007576040517fa3402a3800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b613022898b8a60405180602001604052806000815250614132565b9a9950505050505050505050565b600761303b82612098565b600881111561304c5761304c614bf9565b03613083576040517f44f967fa00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000818152600a6020908152604091829020825161018081018452815473ffffffffffffffffffffffffffffffffffffffff811680835263ffffffff74010000000000000000000000000000000000000000808404821696850196909652780100000000000000000000000000000000000000000000000083048116968401969096527c01000000000000000000000000000000000000000000000000000000009091048516606083015260019092015480851660808301526401000000008104851660a0830152680100000000000000008104851660c08301526c010000000000000000000000008104851660e0830152700100000000000000000000000000000000810490941661010082015260ff9284048316151561012082015275010000000000000000000000000000000000000000008404831615156101408201527601000000000000000000000000000000000000000000009093049091161515610160830152331480159061321357508060e0015163ffffffff1661321082600001516001420361359a565b10155b1561324a576040517f7d78031200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000828152600a60205260409081902060010180547fffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff16750100000000000000000000000000000000000000000017905560085490517f0dc051f80000000000000000000000000000000000000000000000000000000081526004810184905273ffffffffffffffffffffffffffffffffffffffff90911690630dc051f890602401602060405180830381865afa158015613309573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061332d9190615356565b156133b7576008546040517fc4d252f50000000000000000000000000000000000000000000000000000000081526004810184905273ffffffffffffffffffffffffffffffffffffffff9091169063c4d252f590602401600060405180830381600087803b15801561339e57600080fd5b505af11580156133b2573d6000803e3d6000fd5b505050505b6040518281527f88ae8321c96cee88d802409f3677f889d8a6743c4631b069fe600a3a9b07e020906020015b60405180910390a15050565b60005462010000900473ffffffffffffffffffffffffffffffffffffffff163314613446576040517fd238ed5900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000181108061349357507f00000000000000000000000000000000000000000000000000000000000003e881115b806134be5750600754760100000000000000000000000000000000000000000000900461ffff168110155b156134f5576040517f81b64e1a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600754604080517401000000000000000000000000000000000000000090920461ffff168252602082018390527f3597f3d5106fd545a99b5a9cd1e0e7a985f0477ec13aa8c739119325d747fb35910160405180910390a16007805461ffff90921674010000000000000000000000000000000000000000027fffffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffff909216919091179055565b6007546040517f3a46b1a800000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8481166004830152602482018490526000921690633a46b1a890604401602060405180830381865afa158015613612573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125de9190615072565b60005462010000900473ffffffffffffffffffffffffffffffffffffffff16331461368d576040517fd238ed5900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000c88110806136da57507f00000000000000000000000000000000000000000000000000000000000007d081115b80613703575060075474010000000000000000000000000000000000000000900461ffff168111155b1561373a576040517f65122d7900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6007546040805176010000000000000000000000000000000000000000000090920461ffff168252602082018390527fcefdafdfb2f62f73b0ac8d13e7f3cd4d2dbd9eecd15571b7ac644d97fa9083b1910160405180910390a16007805461ffff909216760100000000000000000000000000000000000000000000027fffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffffffff909216919091179055565b60005462010000900473ffffffffffffffffffffffffffffffffffffffff16331461383a576040517fd238ed5900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000025881108061388757507f0000000000000000000000000000000000000000000000000000000000dd7c0081115b156138be576040517f8470281a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600854604080517a01000000000000000000000000000000000000000000000000000090920465ffffffffffff168252602082018390527fffc708f072ca56e3d45ef0cb288b96cb9378f5f63e1646868bfbc9c38f4263a1910160405180910390a16008805465ffffffffffff9092167a0100000000000000000000000000000000000000000000000000000279ffffffffffffffffffffffffffffffffffffffffffffffffffff909216919091179055565b60005462010000900473ffffffffffffffffffffffffffffffffffffffff1633146139c8576040517fd238ed5900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611bc38161446a565b60095473ffffffffffffffffffffffffffffffffffffffff163314613a22576040517f16e025ec00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6007613a2d82612098565b6008811115613a3e57613a3e614bf9565b03613a75576040517f44f967fa00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000818152600a6020526040908190206001810180547fffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffff1676010000000000000000000000000000000000000000000017905560085491517f0dc051f800000000000000000000000000000000000000000000000000000000815260048101849052909173ffffffffffffffffffffffffffffffffffffffff1690630dc051f890602401602060405180830381865afa158015613b36573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613b5a9190615356565b15613be4576008546040517fc4d252f50000000000000000000000000000000000000000000000000000000081526004810184905273ffffffffffffffffffffffffffffffffffffffff9091169063c4d252f590602401600060405180830381600087803b158015613bcb57600080fd5b505af1158015613bdf573d6000803e3d6000fd5b505050505b6040518281527f0c8bf601915d1f39ef591226bc69b3becc23fcb3616673c419062aa44beb42da906020016133e3565b3b151590565b600065ffffffffffff821115613c5c576040517fb0a90f3300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5090565b600061ffff821115613c5c576040517fb0a90f3300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600054610100900460ff16613cdf576040517f624bb4ce00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b815160208084019190912060025581519082012060035546600555613d66600254600354604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60208201529081019290925260608201524660808201523060a082015260009060c00160405160208183030381529060405280519060200120905090565b6004555050565b600054610100900460ff16613dae576040517f624bb4ce00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080547fffffffffffffffffffff0000000000000000000000000000000000000000ffff166201000073ffffffffffffffffffffffffffffffffffffffff84169081029190911782556040519091907f8292fce18fa69edf4db7b94ea2e58241df0ae57f97e0a6c9b29067028bf92d76908290a350565b60005462010000900473ffffffffffffffffffffffffffffffffffffffff163314613e7d576040517fd238ed5900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f0000000000000000000000000e9f3382cf2508e3bc83248b5b4707fba86d7ee073ffffffffffffffffffffffffffffffffffffffff16639bb8dcfd613ef77f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5473ffffffffffffffffffffffffffffffffffffffff1690565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b16815273ffffffffffffffffffffffffffffffffffffffff91821660048201529084166024820152604401602060405180830381865afa158015613f68573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613f8c9190615356565b611bc3576040517fc40d973400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff82166004820152602401611f62565b7f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd91435460ff16156140125761400d83614536565b505050565b8273ffffffffffffffffffffffffffffffffffffffff166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa925050508015614097575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820190925261409491810190615072565b60015b6140cd576040517fc0bb20b200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc8114614126576040517f0849b49600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5061400d8383836145ec565b6000600161413f86612098565b600881111561415057614150614bf9565b14614187576040517f8a59eceb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000858152600b6020908152604080832073ffffffffffffffffffffffffffffffffffffffff8816845290915290205460ff16156141f1576040517feb20971100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600283111561422c576040517f3485325a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000858152600b6020908152604080832073ffffffffffffffffffffffffffffffffffffffff88168452825280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055878352600a909152812080549091906142bd90879063ffffffff740100000000000000000000000000000000000000009091041661359a565b905084600003614329576142d08161442a565b825463ffffffff78010000000000000000000000000000000000000000000000008083048216909301169091027fffffffff00000000ffffffffffffffffffffffffffffffffffffffffffffffff9091161782556143e1565b846001036143935761433a8161442a565b825463ffffffff7c01000000000000000000000000000000000000000000000000000000008083048216909301169091027bffffffffffffffffffffffffffffffffffffffffffffffffffffffff9091161782556143e1565b846002036143e1576143a48161442a565b6001830180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000811663ffffffff91821693909301169190911790555b7f0c165c85edbf8f9b99d51793c9429beb9dc2b608a7f81e64623052f829657af3868887848860405161441895949392919061562e565b60405180910390a19695505050505050565b600063ffffffff821115613c5c576040517fb0a90f3300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000805460405173ffffffffffffffffffffffffffffffffffffffff808516936201000090930416917f8292fce18fa69edf4db7b94ea2e58241df0ae57f97e0a6c9b29067028bf92d7691a36000805473ffffffffffffffffffffffffffffffffffffffff80841662010000027fffffffffffffffffffff0000000000000000000000000000000000000000ffff909216919091179091556001541615611bc357600180547fffffffffffffffffffffffff000000000000000000000000000000000000000016905550565b803b614586576040517fc40d973400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff82166004820152602401611f62565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b6145f583614617565b6000825111806146025750805b1561400d57614611838361466c565b50505050565b61462081614536565b60405173ffffffffffffffffffffffffffffffffffffffff821681527fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b9060200160405180910390a150565b6060823b6146a6576040517f37f2022900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000808473ffffffffffffffffffffffffffffffffffffffff16846040516146ce919061567a565b600060405180830381855af49150503d8060008114614709576040519150601f19603f3d011682016040523d82523d6000602084013e61470e565b606091505b509150915061471d8282614726565b95945050505050565b6060821561473557508061106e565b8151156147455781518083602001fd5b6040517f62536b1000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006020828403121561478957600080fd5b5035919050565b803573ffffffffffffffffffffffffffffffffffffffff811681146147b457600080fd5b919050565b600080600080600080600060e0888a0312156147d457600080fd5b6147dd88614790565b96506147eb60208901614790565b95506147f960408901614790565b969995985095966060810135965060808101359560a0820135955060c0909101359350915050565b60006020828403121561483357600080fd5b6125de82614790565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff811182821017156148b2576148b261483c565b604052919050565b600067ffffffffffffffff8211156148d4576148d461483c565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b600082601f83011261491157600080fd5b813561492461491f826148ba565b61486b565b81815284602083860101111561493957600080fd5b816020850160208301376000918101602001919091529392505050565b60008060006060848603121561496b57600080fd5b8335925060208401359150604084013567ffffffffffffffff81111561499057600080fd5b61499c86828701614900565b9150509250925092565b815173ffffffffffffffffffffffffffffffffffffffff168152610180810160208301516149dc602084018263ffffffff169052565b5060408301516149f4604084018263ffffffff169052565b506060830151614a0c606084018263ffffffff169052565b506080830151614a24608084018263ffffffff169052565b5060a0830151614a3c60a084018263ffffffff169052565b5060c0830151614a5460c084018263ffffffff169052565b5060e0830151614a6c60e084018263ffffffff169052565b506101008381015163ffffffff16908301526101208084015115159083015261014080840151151590830152610160928301511515929091019190915290565b60008060408385031215614abf57600080fd5b614ac883614790565b9150602083013567ffffffffffffffff811115614ae457600080fd5b614af085828601614900565b9150509250929050565b60008083601f840112614b0c57600080fd5b50813567ffffffffffffffff811115614b2457600080fd5b6020830191508360208260051b8501011115614b3f57600080fd5b9250929050565b60008060008060008060008060a0898b031215614b6257600080fd5b883567ffffffffffffffff80821115614b7a57600080fd5b614b868c838d01614afa565b909a50985060208b0135915080821115614b9f57600080fd5b614bab8c838d01614afa565b909850965060408b0135915080821115614bc457600080fd5b50614bd18b828c01614afa565b90955093505060608901359150614bea60808a01614790565b90509295985092959890939650565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b6020810160098310614c63577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b91905290565b60008060408385031215614c7c57600080fd5b50508035926020909101359150565b600067ffffffffffffffff821115614ca557614ca561483c565b5060051b60200190565b600082601f830112614cc057600080fd5b81356020614cd061491f83614c8b565b82815260059290921b84018101918181019086841115614cef57600080fd5b8286015b84811015614d1157614d0481614790565b8352918301918301614cf3565b509695505050505050565b600082601f830112614d2d57600080fd5b81356020614d3d61491f83614c8b565b82815260059290921b84018101918181019086841115614d5c57600080fd5b8286015b84811015614d115780358352918301918301614d60565b6000614d8561491f84614c8b565b8381529050602080820190600585901b840186811115614da457600080fd5b845b81811015614de057803567ffffffffffffffff811115614dc65760008081fd5b614dd289828901614900565b855250928201928201614da6565b505050509392505050565b600082601f830112614dfc57600080fd5b6125de83833560208501614d77565b60008060008060808587031215614e2157600080fd5b843567ffffffffffffffff80821115614e3957600080fd5b614e4588838901614caf565b95506020870135915080821115614e5b57600080fd5b614e6788838901614d1c565b94506040870135915080821115614e7d57600080fd5b614e8988838901614deb565b93506060870135915080821115614e9f57600080fd5b50614eac87828801614900565b91505092959194509250565b60005b83811015614ed3578181015183820152602001614ebb565b50506000910152565b60008151808452614ef4816020860160208601614eb8565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6020815260006125de6020830184614edc565b600080600080600060a08688031215614f5157600080fd5b853567ffffffffffffffff80821115614f6957600080fd5b614f7589838a01614caf565b96506020880135915080821115614f8b57600080fd5b614f9789838a01614d1c565b95506040880135915080821115614fad57600080fd5b50614fba88828901614deb565b93505060608601359150614fd060808701614790565b90509295509295909350565b600080600080600080600060e0888a031215614ff757600080fd5b61500088614790565b9650602088013595506040880135945060608801359350608088013560ff8116811461502b57600080fd5b9699959850939692959460a0840135945060c09093013592915050565b6000806040838503121561505b57600080fd5b61506483614790565b946020939093013593505050565b60006020828403121561508457600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b6000602082840312156150cc57600080fd5b815167ffffffffffffffff8111156150e357600080fd5b8201601f810184136150f457600080fd5b805161510261491f826148ba565b81815285602083850101111561511757600080fd5b61471d826020830160208601614eb8565b6000825161513a818460208701614eb8565b7f20474f5600000000000000000000000000000000000000000000000000000000920191825250600401919050565b60006125de368484614d77565b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b81835260006020808501808196508560051b810191508460005b8781101561526257828403895281357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe188360301811261521857600080fd5b8701858101903567ffffffffffffffff81111561523457600080fd5b80360382131561524357600080fd5b61524e868284615176565b9a87019a95505050908401906001016151d9565b5091979650505050505050565b60a0808252810188905260008960c08301825b8b8110156152bd5773ffffffffffffffffffffffffffffffffffffffff6152a884614790565b16825260209283019290910190600101615282565b5083810360208501528881527f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8911156152f657600080fd5b8860051b9150818a6020830137018281036020908101604085015261531e90820187896151bf565b915050836060830152615349608083018473ffffffffffffffffffffffffffffffffffffffff169052565b9998505050505050505050565b60006020828403121561536857600080fd5b815180151581146125de57600080fd5b600081518084526020808501945080840160005b838110156153be57815173ffffffffffffffffffffffffffffffffffffffff168752958201959082019060010161538c565b509495945050505050565b600081518084526020808501945080840160005b838110156153be578151875295820195908201906001016153dd565b600081518084526020808501808196508360051b8101915082860160005b8581101561526257828403895261542f848351614edc565b98850198935090840190600101615417565b600061024089835280602084015261545b8184018a615378565b9050828103604084015261546f81896153c9565b9050828103606084015261548381886153f9565b905082810360808401526154978187614edc565b9150508360a083015282546154da60c0840173ffffffffffffffffffffffffffffffffffffffff831673ffffffffffffffffffffffffffffffffffffffff169052565b63ffffffff60a082901c811660e085015260c082901c811661010085015260e082901c610120850152600185015463ffffffff8282161661014086015291506155316101608501828460201c1663ffffffff169052565b6155496101808501828460401c1663ffffffff169052565b6155616101a08501828460601c1663ffffffff169052565b6155796101c08501828460801c1663ffffffff169052565b5061558f6101e0840160ff8360a01c1615159052565b6155a4610200840160ff8360a81c1615159052565b6155b9610220840160ff8360b01c1615159052565b5098975050505050505050565b60a0815260006155d960a0830188615378565b82810360208401526155eb81886153c9565b905082810360408401526155ff81876153f9565b91505083606083015273ffffffffffffffffffffffffffffffffffffffff831660808301529695505050505050565b73ffffffffffffffffffffffffffffffffffffffff8616815284602082015283604082015282606082015260a06080820152600061566f60a0830184614edc565b979650505050505050565b6000825161568c818460208701614eb8565b919091019291505056fea264697066735822122064b51134927b2d8ab75f42bea6c26a1cad09ae79e3446254c7140cc4d5077ab764736f6c63430008100033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000000e9f3382cf2508e3bc83248b5b4707fba86d7ee0
-----Decoded View---------------
Arg [0] : _manager (address): 0x0E9F3382Cf2508E3bc83248B5b4707FbA86D7Ee0
-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 0000000000000000000000000e9f3382cf2508e3bc83248b5b4707fba86d7ee0
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.