Overview
ETH Balance
0.31228087561259894 ETH
Eth Value
$1,030.59 (@ $3,300.21/ETH)More Info
Private Name Tags
ContractCreator
Latest 25 from a total of 216 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
Value | ||||
---|---|---|---|---|---|---|---|---|---|
Transfer Prop Up... | 18688036 | 215 days ago | IN | 0 ETH | 0.00344568 | ||||
Post Update | 18687968 | 215 days ago | IN | 0 ETH | 0.01074632 | ||||
Post Update | 18687946 | 215 days ago | IN | 0 ETH | 0.00384397 | ||||
Post Update | 18685051 | 216 days ago | IN | 0 ETH | 0.01006531 | ||||
Transfer Prop Up... | 18681335 | 216 days ago | IN | 0 ETH | 0.003916 | ||||
Post Update | 18677398 | 217 days ago | IN | 0 ETH | 0.00428985 | ||||
Transfer Prop Up... | 18677341 | 217 days ago | IN | 0 ETH | 0.00312751 | ||||
Post Update | 18674785 | 217 days ago | IN | 0 ETH | 0.00501038 | ||||
Post Update | 18670367 | 218 days ago | IN | 0 ETH | 0.00333235 | ||||
Post Update | 18669686 | 218 days ago | IN | 0 ETH | 0.00322439 | ||||
Post Update | 18669640 | 218 days ago | IN | 0 ETH | 0.00289226 | ||||
Transfer Prop Up... | 18669613 | 218 days ago | IN | 0 ETH | 0.00267429 | ||||
Post Update | 18653695 | 220 days ago | IN | 0 ETH | 0.00203417 | ||||
Transfer Prop Up... | 18653321 | 220 days ago | IN | 0 ETH | 0.00165419 | ||||
Post Update | 18653154 | 220 days ago | IN | 0 ETH | 0.00212 | ||||
Transfer Prop Up... | 18650776 | 220 days ago | IN | 0 ETH | 0.00188751 | ||||
Post Update | 18635822 | 223 days ago | IN | 0 ETH | 0.00473784 | ||||
Post Update | 18629234 | 223 days ago | IN | 0 ETH | 0.01265792 | ||||
Transfer Prop Up... | 18618983 | 225 days ago | IN | 0 ETH | 0.00255985 | ||||
Post Update | 18612252 | 226 days ago | IN | 0 ETH | 0.00320641 | ||||
Post Update | 18601088 | 227 days ago | IN | 0 ETH | 0.00521027 | ||||
Post Update | 18597049 | 228 days ago | IN | 0 ETH | 0.00262348 | ||||
Transfer Prop Up... | 18596979 | 228 days ago | IN | 0 ETH | 0.00186825 | ||||
Post Update | 18596325 | 228 days ago | IN | 0 ETH | 0.00181446 | ||||
Post Update | 18595261 | 228 days ago | IN | 0 ETH | 0.00262612 |
Latest 25 internal transactions (View All)
Advanced mode:
Parent Transaction Hash | Block | From | To | Value | ||
---|---|---|---|---|---|---|
18687968 | 215 days ago | 0.00617246 ETH | ||||
18687946 | 215 days ago | 0.00389891 ETH | ||||
18685051 | 216 days ago | 0.01026234 ETH | ||||
18677398 | 217 days ago | 0.00418375 ETH | ||||
18674785 | 217 days ago | 0.0038404 ETH | ||||
18670367 | 218 days ago | 0.00334476 ETH | ||||
18669686 | 218 days ago | 0.0033927 ETH | ||||
18669640 | 218 days ago | 0.00311798 ETH | ||||
18653695 | 220 days ago | 0.00209972 ETH | ||||
18653154 | 220 days ago | 0.00205719 ETH | ||||
18635822 | 223 days ago | 0.00410972 ETH | ||||
18629234 | 223 days ago | 0.0096426 ETH | ||||
18612252 | 226 days ago | 0.00316794 ETH | ||||
18601088 | 227 days ago | 0.00296808 ETH | ||||
18597049 | 228 days ago | 0.00256603 ETH | ||||
18596325 | 228 days ago | 0.00195386 ETH | ||||
18595261 | 228 days ago | 0.00290806 ETH | ||||
18595049 | 228 days ago | 0.00336718 ETH | ||||
18595047 | 228 days ago | 0.0035369 ETH | ||||
18595036 | 228 days ago | 0.00328727 ETH | ||||
18594871 | 228 days ago | 0.00333803 ETH | ||||
18585625 | 230 days ago | 0.00650813 ETH | ||||
18581281 | 230 days ago | 0.00316223 ETH | ||||
18578043 | 231 days ago | 0.00438771 ETH | ||||
18573213 | 231 days ago | 0.00499689 ETH |
Loading...
Loading
Contract Name:
Propdates
Compiler Version
v0.8.17+commit.8df45f5f
Optimization Enabled:
Yes with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity ^0.8.17; import {NounsDAOLogicV2} from "lib/nouns-monorepo/packages/nouns-contracts/contracts/governance/NounsDAOLogicV2.sol"; import "lib/nouns-monorepo/packages/nouns-contracts/contracts/governance/NounsDAOInterfaces.sol"; import {GasRefund} from "./GasRefund.sol"; contract Propdates { struct PropdateInfo { // address which can post updates for this prop address propUpdateAdmin; // when was the last update was posted uint88 lastUpdated; // is the primary work of the proposal considered done bool isCompleted; } event PropUpdateAdminTransferStarted(uint256 indexed propId, address indexed oldAdmin, address indexed newAdmin); event PropUpdateAdminTransfered(uint256 indexed propId, address indexed oldAdmin, address indexed newAdmin); event PostUpdate(uint256 indexed propId, bool indexed isCompleted, string update); error OnlyPropUpdateAdmin(); error OnlyPendingPropUpdateAdmin(); error NoZeroAddress(); address payable public constant NOUNS_DAO = payable(0x6f3E6272A167e8AcCb32072d08E0957F9c79223d); mapping(uint256 => address) public pendingPropUpdateAdmin; mapping(uint256 => PropdateInfo) internal _propdateInfo; // allow receiving ETH for gas refunds receive() external payable {} /// @notice Transfers prop update admin power to a new address /// @dev reverts if the new admin is the zero address /// @dev if current admin is zero address, reverts unless msg.sender is prop proposer /// @dev if current admin is not zero address, reverts unless msg.sender is current admin /// @dev requires newAdmin to accept the admin power in a separate transaction /// @param propId The id of the prop /// @param newAdmin The address to transfer admin power to function transferPropUpdateAdmin(uint256 propId, address newAdmin) external { if (newAdmin == address(0)) { // block transferring to zero address because it creates a weird state // where the prop proposer has control again revert NoZeroAddress(); } address currentAdmin = _propdateInfo[propId].propUpdateAdmin; if ( msg.sender != currentAdmin && !(currentAdmin == address(0) && NounsDAOLogicV2(NOUNS_DAO).proposals(propId).proposer == msg.sender) ) { revert OnlyPropUpdateAdmin(); } pendingPropUpdateAdmin[propId] = newAdmin; emit PropUpdateAdminTransferStarted(propId, currentAdmin, newAdmin); } /// @notice Accepts the pending prop update admin power /// @param propId The id of the prop function acceptPropUpdateAdmin(uint256 propId) external { if (msg.sender != pendingPropUpdateAdmin[propId]) { revert OnlyPendingPropUpdateAdmin(); } _acceptPropUpdateAdmin(propId); } /// @notice Posts an update for a prop /// @dev reverts unless msg.sender is propUpdateAdmin or pendingPropUpdateAdmin /// @param propId The id of the prop /// @param isCompleted Whether the primary work of the prop is considered done /// @param update A string describing the update function postUpdate(uint256 propId, bool isCompleted, string calldata update) external { uint256 startGas = gasleft(); if (msg.sender != _propdateInfo[propId].propUpdateAdmin) { if (msg.sender == pendingPropUpdateAdmin[propId]) { // don't love the side effect here, but it saves a tx and so seems worth it? // could also just make it multicallable, but this is simpler for clients _acceptPropUpdateAdmin(propId); } else { revert OnlyPropUpdateAdmin(); } } _propdateInfo[propId].lastUpdated = uint88(block.timestamp); // only set this value if true, so that it can't be unset if (isCompleted) { _propdateInfo[propId].isCompleted = true; } emit PostUpdate(propId, isCompleted, update); if (NounsDAOLogicV2(NOUNS_DAO).proposals(propId).executed) { GasRefund.refundGas(startGas); } } /// @notice Returns the propdate info for a prop /// @param propId The id of the prop /// @return info propdate info function propdateInfo(uint256 propId) external view returns (PropdateInfo memory) { return _propdateInfo[propId]; } function _acceptPropUpdateAdmin(uint256 propId) internal { delete pendingPropUpdateAdmin[propId]; address oldAdmin = _propdateInfo[propId].propUpdateAdmin; _propdateInfo[propId].propUpdateAdmin = msg.sender; emit PropUpdateAdminTransfered(propId, oldAdmin, msg.sender); } }
// SPDX-License-Identifier: BSD-3-Clause /// @title The Nouns DAO logic version 2 /********************************* * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ * * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ * * ░░░░░░█████████░░█████████░░░ * * ░░░░░░██░░░████░░██░░░████░░░ * * ░░██████░░░████████░░░████░░░ * * ░░██░░██░░░████░░██░░░████░░░ * * ░░██░░██░░░████░░██░░░████░░░ * * ░░░░░░█████████░░█████████░░░ * * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ * * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ * *********************************/ // LICENSE // NounsDAOLogicV2.sol is a modified version of Compound Lab's GovernorBravoDelegate.sol: // https://github.com/compound-finance/compound-protocol/blob/b9b14038612d846b83f8a009a82c38974ff2dcfe/contracts/Governance/GovernorBravoDelegate.sol // // GovernorBravoDelegate.sol source code Copyright 2020 Compound Labs, Inc. licensed under the BSD-3-Clause license. // With modifications by Nounders DAO. // // Additional conditions of BSD-3-Clause can be found here: https://opensource.org/licenses/BSD-3-Clause // // MODIFICATIONS // See NounsDAOLogicV1 for initial GovernorBravoDelegate modifications. // NounsDAOLogicV2 adds: // - `quorumParamsCheckpoints`, which store dynamic quorum parameters checkpoints // to be used when calculating the dynamic quorum. // - `_setDynamicQuorumParams(DynamicQuorumParams memory params)`, which allows the // DAO to update the dynamic quorum parameters' values. // - `getDynamicQuorumParamsAt(uint256 blockNumber_)` // - Individual setters of the DynamicQuorumParams members: // - `_setMinQuorumVotesBPS(uint16 newMinQuorumVotesBPS)` // - `_setMaxQuorumVotesBPS(uint16 newMaxQuorumVotesBPS)` // - `_setQuorumCoefficient(uint32 newQuorumCoefficient)` // - `minQuorumVotes` and `maxQuorumVotes`, which returns the current min and // max quorum votes using the current Noun supply. // - New `Proposal` struct member: // - `totalSupply` used in dynamic quorum calculation. // - `creationBlock` used for retrieving checkpoints of votes and dynamic quorum params. This now // allows changing `votingDelay` without affecting the checkpoints lookup. // - `quorumVotes(uint256 proposalId)`, which calculates and returns the dynamic // quorum for a specific proposal. // - `proposals(uint256 proposalId)` instead of the implicit getter, to avoid stack-too-deep error // // NounsDAOLogicV2 removes: // - `quorumVotes()` has been replaced by `quorumVotes(uint256 proposalId)`. pragma solidity ^0.8.6; import './NounsDAOInterfaces.sol'; contract NounsDAOLogicV2 is NounsDAOStorageV2, NounsDAOEventsV2 { /// @notice The name of this contract string public constant name = 'Nouns DAO'; /// @notice The minimum setable proposal threshold uint256 public constant MIN_PROPOSAL_THRESHOLD_BPS = 1; // 1 basis point or 0.01% /// @notice The maximum setable proposal threshold uint256 public constant MAX_PROPOSAL_THRESHOLD_BPS = 1_000; // 1,000 basis points or 10% /// @notice The minimum setable voting period uint256 public constant MIN_VOTING_PERIOD = 5_760; // About 24 hours /// @notice The max setable voting period uint256 public constant MAX_VOTING_PERIOD = 80_640; // About 2 weeks /// @notice The min setable voting delay uint256 public constant MIN_VOTING_DELAY = 1; /// @notice The max setable voting delay uint256 public constant MAX_VOTING_DELAY = 40_320; // About 1 week /// @notice The lower bound of minimum quorum votes basis points uint256 public constant MIN_QUORUM_VOTES_BPS_LOWER_BOUND = 200; // 200 basis points or 2% /// @notice The upper bound of minimum quorum votes basis points uint256 public constant MIN_QUORUM_VOTES_BPS_UPPER_BOUND = 2_000; // 2,000 basis points or 20% /// @notice The upper bound of maximum quorum votes basis points uint256 public constant MAX_QUORUM_VOTES_BPS_UPPER_BOUND = 6_000; // 4,000 basis points or 60% /// @notice The maximum setable quorum votes basis points uint256 public constant MAX_QUORUM_VOTES_BPS = 2_000; // 2,000 basis points or 20% /// @notice The maximum number of actions that can be included in a proposal uint256 public constant proposalMaxOperations = 10; // 10 actions /// @notice The maximum priority fee used to cap gas refunds in `castRefundableVote` uint256 public constant MAX_REFUND_PRIORITY_FEE = 2 gwei; /// @notice The vote refund gas overhead, including 7K for ETH transfer and 29K for general transaction overhead uint256 public constant REFUND_BASE_GAS = 36000; /// @notice The maximum gas units the DAO will refund voters on; supports about 9,190 characters uint256 public constant MAX_REFUND_GAS_USED = 200_000; /// @notice The maximum basefee the DAO will refund voters on uint256 public constant MAX_REFUND_BASE_FEE = 200 gwei; /// @notice The EIP-712 typehash for the contract's domain bytes32 public constant DOMAIN_TYPEHASH = keccak256('EIP712Domain(string name,uint256 chainId,address verifyingContract)'); /// @notice The EIP-712 typehash for the ballot struct used by the contract bytes32 public constant BALLOT_TYPEHASH = keccak256('Ballot(uint256 proposalId,uint8 support)'); /// @dev Introduced these errors to reduce contract size, to avoid deployment failure error AdminOnly(); error InvalidMinQuorumVotesBPS(); error InvalidMaxQuorumVotesBPS(); error MinQuorumBPSGreaterThanMaxQuorumBPS(); error UnsafeUint16Cast(); error VetoerOnly(); error PendingVetoerOnly(); error VetoerBurned(); error CantVetoExecutedProposal(); error CantCancelExecutedProposal(); /** * @notice Used to initialize the contract during delegator contructor * @param timelock_ The address of the NounsDAOExecutor * @param nouns_ The address of the NOUN tokens * @param vetoer_ The address allowed to unilaterally veto proposals * @param votingPeriod_ The initial voting period * @param votingDelay_ The initial voting delay * @param proposalThresholdBPS_ The initial proposal threshold in basis points * @param dynamicQuorumParams_ The initial dynamic quorum parameters */ function initialize( address timelock_, address nouns_, address vetoer_, uint256 votingPeriod_, uint256 votingDelay_, uint256 proposalThresholdBPS_, DynamicQuorumParams calldata dynamicQuorumParams_ ) public virtual { require(address(timelock) == address(0), 'NounsDAO::initialize: can only initialize once'); if (msg.sender != admin) { revert AdminOnly(); } require(timelock_ != address(0), 'NounsDAO::initialize: invalid timelock address'); require(nouns_ != address(0), 'NounsDAO::initialize: invalid nouns address'); require( votingPeriod_ >= MIN_VOTING_PERIOD && votingPeriod_ <= MAX_VOTING_PERIOD, 'NounsDAO::initialize: invalid voting period' ); require( votingDelay_ >= MIN_VOTING_DELAY && votingDelay_ <= MAX_VOTING_DELAY, 'NounsDAO::initialize: invalid voting delay' ); require( proposalThresholdBPS_ >= MIN_PROPOSAL_THRESHOLD_BPS && proposalThresholdBPS_ <= MAX_PROPOSAL_THRESHOLD_BPS, 'NounsDAO::initialize: invalid proposal threshold bps' ); emit VotingPeriodSet(votingPeriod, votingPeriod_); emit VotingDelaySet(votingDelay, votingDelay_); emit ProposalThresholdBPSSet(proposalThresholdBPS, proposalThresholdBPS_); timelock = INounsDAOExecutor(timelock_); nouns = NounsTokenLike(nouns_); vetoer = vetoer_; votingPeriod = votingPeriod_; votingDelay = votingDelay_; proposalThresholdBPS = proposalThresholdBPS_; _setDynamicQuorumParams( dynamicQuorumParams_.minQuorumVotesBPS, dynamicQuorumParams_.maxQuorumVotesBPS, dynamicQuorumParams_.quorumCoefficient ); } struct ProposalTemp { uint256 totalSupply; uint256 proposalThreshold; uint256 latestProposalId; uint256 startBlock; uint256 endBlock; } /** * @notice Function used to propose a new proposal. Sender must have delegates above the proposal threshold * @param targets Target addresses for proposal calls * @param values Eth values for proposal calls * @param signatures Function signatures for proposal calls * @param calldatas Calldatas for proposal calls * @param description String description of the proposal * @return Proposal id of new proposal */ function propose( address[] memory targets, uint256[] memory values, string[] memory signatures, bytes[] memory calldatas, string memory description ) public returns (uint256) { ProposalTemp memory temp; temp.totalSupply = nouns.totalSupply(); temp.proposalThreshold = bps2Uint(proposalThresholdBPS, temp.totalSupply); require( nouns.getPriorVotes(msg.sender, block.number - 1) > temp.proposalThreshold, 'NounsDAO::propose: proposer votes below proposal threshold' ); require( targets.length == values.length && targets.length == signatures.length && targets.length == calldatas.length, 'NounsDAO::propose: proposal function information arity mismatch' ); require(targets.length != 0, 'NounsDAO::propose: must provide actions'); require(targets.length <= proposalMaxOperations, 'NounsDAO::propose: too many actions'); temp.latestProposalId = latestProposalIds[msg.sender]; if (temp.latestProposalId != 0) { ProposalState proposersLatestProposalState = state(temp.latestProposalId); require( proposersLatestProposalState != ProposalState.Active, 'NounsDAO::propose: one live proposal per proposer, found an already active proposal' ); require( proposersLatestProposalState != ProposalState.Pending, 'NounsDAO::propose: one live proposal per proposer, found an already pending proposal' ); } temp.startBlock = block.number + votingDelay; temp.endBlock = temp.startBlock + votingPeriod; proposalCount++; Proposal storage newProposal = _proposals[proposalCount]; newProposal.id = proposalCount; newProposal.proposer = msg.sender; newProposal.proposalThreshold = temp.proposalThreshold; newProposal.eta = 0; newProposal.targets = targets; newProposal.values = values; newProposal.signatures = signatures; newProposal.calldatas = calldatas; newProposal.startBlock = temp.startBlock; newProposal.endBlock = temp.endBlock; newProposal.forVotes = 0; newProposal.againstVotes = 0; newProposal.abstainVotes = 0; newProposal.canceled = false; newProposal.executed = false; newProposal.vetoed = false; newProposal.totalSupply = temp.totalSupply; newProposal.creationBlock = block.number; latestProposalIds[newProposal.proposer] = newProposal.id; /// @notice Maintains backwards compatibility with GovernorBravo events emit ProposalCreated( newProposal.id, msg.sender, targets, values, signatures, calldatas, newProposal.startBlock, newProposal.endBlock, description ); /// @notice Updated event with `proposalThreshold` and `minQuorumVotes` /// @notice `minQuorumVotes` is always zero since V2 introduces dynamic quorum with checkpoints emit ProposalCreatedWithRequirements( newProposal.id, msg.sender, targets, values, signatures, calldatas, newProposal.startBlock, newProposal.endBlock, newProposal.proposalThreshold, minQuorumVotes(), description ); return newProposal.id; } /** * @notice Queues a proposal of state succeeded * @param proposalId The id of the proposal to queue */ function queue(uint256 proposalId) external { require( state(proposalId) == ProposalState.Succeeded, 'NounsDAO::queue: proposal can only be queued if it is succeeded' ); Proposal storage proposal = _proposals[proposalId]; uint256 eta = block.timestamp + timelock.delay(); for (uint256 i = 0; i < proposal.targets.length; i++) { queueOrRevertInternal( proposal.targets[i], proposal.values[i], proposal.signatures[i], proposal.calldatas[i], eta ); } proposal.eta = eta; emit ProposalQueued(proposalId, eta); } function queueOrRevertInternal( address target, uint256 value, string memory signature, bytes memory data, uint256 eta ) internal { require( !timelock.queuedTransactions(keccak256(abi.encode(target, value, signature, data, eta))), 'NounsDAO::queueOrRevertInternal: identical proposal action already queued at eta' ); timelock.queueTransaction(target, value, signature, data, eta); } /** * @notice Executes a queued proposal if eta has passed * @param proposalId The id of the proposal to execute */ function execute(uint256 proposalId) external { require( state(proposalId) == ProposalState.Queued, 'NounsDAO::execute: proposal can only be executed if it is queued' ); Proposal storage proposal = _proposals[proposalId]; proposal.executed = true; for (uint256 i = 0; i < proposal.targets.length; i++) { timelock.executeTransaction( proposal.targets[i], proposal.values[i], proposal.signatures[i], proposal.calldatas[i], proposal.eta ); } emit ProposalExecuted(proposalId); } /** * @notice Cancels a proposal only if sender is the proposer, or proposer delegates dropped below proposal threshold * @param proposalId The id of the proposal to cancel */ function cancel(uint256 proposalId) external { if (state(proposalId) == ProposalState.Executed) { revert CantCancelExecutedProposal(); } Proposal storage proposal = _proposals[proposalId]; require( msg.sender == proposal.proposer || nouns.getPriorVotes(proposal.proposer, block.number - 1) <= proposal.proposalThreshold, 'NounsDAO::cancel: proposer above threshold' ); proposal.canceled = true; for (uint256 i = 0; i < proposal.targets.length; i++) { timelock.cancelTransaction( proposal.targets[i], proposal.values[i], proposal.signatures[i], proposal.calldatas[i], proposal.eta ); } emit ProposalCanceled(proposalId); } /** * @notice Vetoes a proposal only if sender is the vetoer and the proposal has not been executed. * @param proposalId The id of the proposal to veto */ function veto(uint256 proposalId) external { if (vetoer == address(0)) { revert VetoerBurned(); } if (msg.sender != vetoer) { revert VetoerOnly(); } if (state(proposalId) == ProposalState.Executed) { revert CantVetoExecutedProposal(); } Proposal storage proposal = _proposals[proposalId]; proposal.vetoed = true; for (uint256 i = 0; i < proposal.targets.length; i++) { timelock.cancelTransaction( proposal.targets[i], proposal.values[i], proposal.signatures[i], proposal.calldatas[i], proposal.eta ); } emit ProposalVetoed(proposalId); } /** * @notice Gets actions of a proposal * @param proposalId the id of the proposal * @return targets * @return values * @return signatures * @return calldatas */ function getActions(uint256 proposalId) external view returns ( address[] memory targets, uint256[] memory values, string[] memory signatures, bytes[] memory calldatas ) { Proposal storage p = _proposals[proposalId]; return (p.targets, p.values, p.signatures, p.calldatas); } /** * @notice Gets the receipt for a voter on a given proposal * @param proposalId the id of proposal * @param voter The address of the voter * @return The voting receipt */ function getReceipt(uint256 proposalId, address voter) external view returns (Receipt memory) { return _proposals[proposalId].receipts[voter]; } /** * @notice Gets the state of a proposal * @param proposalId The id of the proposal * @return Proposal state */ function state(uint256 proposalId) public view returns (ProposalState) { require(proposalCount >= proposalId, 'NounsDAO::state: invalid proposal id'); Proposal storage proposal = _proposals[proposalId]; if (proposal.vetoed) { return ProposalState.Vetoed; } else if (proposal.canceled) { return ProposalState.Canceled; } else if (block.number <= proposal.startBlock) { return ProposalState.Pending; } else if (block.number <= proposal.endBlock) { return ProposalState.Active; } else if (proposal.forVotes <= proposal.againstVotes || proposal.forVotes < quorumVotes(proposal.id)) { return ProposalState.Defeated; } else if (proposal.eta == 0) { return ProposalState.Succeeded; } else if (proposal.executed) { return ProposalState.Executed; } else if (block.timestamp >= proposal.eta + timelock.GRACE_PERIOD()) { return ProposalState.Expired; } else { return ProposalState.Queued; } } /** * @notice Returns the proposal details given a proposal id. * The `quorumVotes` member holds the *current* quorum, given the current votes. * @param proposalId the proposal id to get the data for * @return A `ProposalCondensed` struct with the proposal data */ function proposals(uint256 proposalId) external view returns (ProposalCondensed memory) { Proposal storage proposal = _proposals[proposalId]; return ProposalCondensed({ id: proposal.id, proposer: proposal.proposer, proposalThreshold: proposal.proposalThreshold, quorumVotes: quorumVotes(proposal.id), eta: proposal.eta, startBlock: proposal.startBlock, endBlock: proposal.endBlock, forVotes: proposal.forVotes, againstVotes: proposal.againstVotes, abstainVotes: proposal.abstainVotes, canceled: proposal.canceled, vetoed: proposal.vetoed, executed: proposal.executed, totalSupply: proposal.totalSupply, creationBlock: proposal.creationBlock }); } /** * @notice Cast a vote for a proposal * @param proposalId The id of the proposal to vote on * @param support The support value for the vote. 0=against, 1=for, 2=abstain */ function castVote(uint256 proposalId, uint8 support) external { emit VoteCast(msg.sender, proposalId, support, castVoteInternal(msg.sender, proposalId, support), ''); } /** * @notice Cast a vote for a proposal, asking the DAO to refund gas costs. * Users with > 0 votes receive refunds. Refunds are partial when using a gas priority fee higher than the DAO's cap. * Refunds are partial when the DAO's balance is insufficient. * No refund is sent when the DAO's balance is empty. No refund is sent to users with no votes. * Voting takes place regardless of refund success. * @param proposalId The id of the proposal to vote on * @param support The support value for the vote. 0=against, 1=for, 2=abstain * @dev Reentrancy is defended against in `castVoteInternal` at the `receipt.hasVoted == false` require statement. */ function castRefundableVote(uint256 proposalId, uint8 support) external { castRefundableVoteInternal(proposalId, support, ''); } /** * @notice Cast a vote for a proposal, asking the DAO to refund gas costs. * Users with > 0 votes receive refunds. Refunds are partial when using a gas priority fee higher than the DAO's cap. * Refunds are partial when the DAO's balance is insufficient. * No refund is sent when the DAO's balance is empty. No refund is sent to users with no votes. * Voting takes place regardless of refund success. * @param proposalId The id of the proposal to vote on * @param support The support value for the vote. 0=against, 1=for, 2=abstain * @param reason The reason given for the vote by the voter * @dev Reentrancy is defended against in `castVoteInternal` at the `receipt.hasVoted == false` require statement. */ function castRefundableVoteWithReason( uint256 proposalId, uint8 support, string calldata reason ) external { castRefundableVoteInternal(proposalId, support, reason); } /** * @notice Internal function that carries out refundable voting logic * @param proposalId The id of the proposal to vote on * @param support The support value for the vote. 0=against, 1=for, 2=abstain * @param reason The reason given for the vote by the voter * @dev Reentrancy is defended against in `castVoteInternal` at the `receipt.hasVoted == false` require statement. */ function castRefundableVoteInternal( uint256 proposalId, uint8 support, string memory reason ) internal { uint256 startGas = gasleft(); uint96 votes = castVoteInternal(msg.sender, proposalId, support); emit VoteCast(msg.sender, proposalId, support, votes, reason); if (votes > 0) { _refundGas(startGas); } } /** * @notice Cast a vote for a proposal with a reason * @param proposalId The id of the proposal to vote on * @param support The support value for the vote. 0=against, 1=for, 2=abstain * @param reason The reason given for the vote by the voter */ function castVoteWithReason( uint256 proposalId, uint8 support, string calldata reason ) external { emit VoteCast(msg.sender, proposalId, support, castVoteInternal(msg.sender, proposalId, support), reason); } /** * @notice Cast a vote for a proposal by signature * @dev External function that accepts EIP-712 signatures for voting on proposals. */ function castVoteBySig( uint256 proposalId, uint8 support, uint8 v, bytes32 r, bytes32 s ) external { bytes32 domainSeparator = keccak256( abi.encode(DOMAIN_TYPEHASH, keccak256(bytes(name)), getChainIdInternal(), address(this)) ); bytes32 structHash = keccak256(abi.encode(BALLOT_TYPEHASH, proposalId, support)); bytes32 digest = keccak256(abi.encodePacked('\x19\x01', domainSeparator, structHash)); address signatory = ecrecover(digest, v, r, s); require(signatory != address(0), 'NounsDAO::castVoteBySig: invalid signature'); emit VoteCast(signatory, proposalId, support, castVoteInternal(signatory, proposalId, support), ''); } /** * @notice Internal function that caries out voting logic * @param voter The voter that is casting their vote * @param proposalId The id of the proposal to vote on * @param support The support value for the vote. 0=against, 1=for, 2=abstain * @return The number of votes cast */ function castVoteInternal( address voter, uint256 proposalId, uint8 support ) internal returns (uint96) { require(state(proposalId) == ProposalState.Active, 'NounsDAO::castVoteInternal: voting is closed'); require(support <= 2, 'NounsDAO::castVoteInternal: invalid vote type'); Proposal storage proposal = _proposals[proposalId]; Receipt storage receipt = proposal.receipts[voter]; require(receipt.hasVoted == false, 'NounsDAO::castVoteInternal: voter already voted'); /// @notice: Unlike GovernerBravo, votes are considered from the block the proposal was created in order to normalize quorumVotes and proposalThreshold metrics uint96 votes = nouns.getPriorVotes(voter, proposalCreationBlock(proposal)); if (support == 0) { proposal.againstVotes = proposal.againstVotes + votes; } else if (support == 1) { proposal.forVotes = proposal.forVotes + votes; } else if (support == 2) { proposal.abstainVotes = proposal.abstainVotes + votes; } receipt.hasVoted = true; receipt.support = support; receipt.votes = votes; return votes; } /** * @notice Admin function for setting the voting delay * @param newVotingDelay new voting delay, in blocks */ function _setVotingDelay(uint256 newVotingDelay) external { if (msg.sender != admin) { revert AdminOnly(); } require( newVotingDelay >= MIN_VOTING_DELAY && newVotingDelay <= MAX_VOTING_DELAY, 'NounsDAO::_setVotingDelay: invalid voting delay' ); uint256 oldVotingDelay = votingDelay; votingDelay = newVotingDelay; emit VotingDelaySet(oldVotingDelay, votingDelay); } /** * @notice Admin function for setting the voting period * @param newVotingPeriod new voting period, in blocks */ function _setVotingPeriod(uint256 newVotingPeriod) external { if (msg.sender != admin) { revert AdminOnly(); } require( newVotingPeriod >= MIN_VOTING_PERIOD && newVotingPeriod <= MAX_VOTING_PERIOD, 'NounsDAO::_setVotingPeriod: invalid voting period' ); uint256 oldVotingPeriod = votingPeriod; votingPeriod = newVotingPeriod; emit VotingPeriodSet(oldVotingPeriod, votingPeriod); } /** * @notice Admin function for setting the proposal threshold basis points * @dev newProposalThresholdBPS must be greater than the hardcoded min * @param newProposalThresholdBPS new proposal threshold */ function _setProposalThresholdBPS(uint256 newProposalThresholdBPS) external { if (msg.sender != admin) { revert AdminOnly(); } require( newProposalThresholdBPS >= MIN_PROPOSAL_THRESHOLD_BPS && newProposalThresholdBPS <= MAX_PROPOSAL_THRESHOLD_BPS, 'NounsDAO::_setProposalThreshold: invalid proposal threshold bps' ); uint256 oldProposalThresholdBPS = proposalThresholdBPS; proposalThresholdBPS = newProposalThresholdBPS; emit ProposalThresholdBPSSet(oldProposalThresholdBPS, proposalThresholdBPS); } /** * @notice Admin function for setting the minimum quorum votes bps * @param newMinQuorumVotesBPS minimum quorum votes bps * Must be between `MIN_QUORUM_VOTES_BPS_LOWER_BOUND` and `MIN_QUORUM_VOTES_BPS_UPPER_BOUND` * Must be lower than or equal to maxQuorumVotesBPS */ function _setMinQuorumVotesBPS(uint16 newMinQuorumVotesBPS) external { if (msg.sender != admin) { revert AdminOnly(); } DynamicQuorumParams memory params = getDynamicQuorumParamsAt(block.number); require( newMinQuorumVotesBPS >= MIN_QUORUM_VOTES_BPS_LOWER_BOUND && newMinQuorumVotesBPS <= MIN_QUORUM_VOTES_BPS_UPPER_BOUND, 'NounsDAO::_setMinQuorumVotesBPS: invalid min quorum votes bps' ); require( newMinQuorumVotesBPS <= params.maxQuorumVotesBPS, 'NounsDAO::_setMinQuorumVotesBPS: min quorum votes bps greater than max' ); uint16 oldMinQuorumVotesBPS = params.minQuorumVotesBPS; params.minQuorumVotesBPS = newMinQuorumVotesBPS; _writeQuorumParamsCheckpoint(params); emit MinQuorumVotesBPSSet(oldMinQuorumVotesBPS, newMinQuorumVotesBPS); } /** * @notice Admin function for setting the maximum quorum votes bps * @param newMaxQuorumVotesBPS maximum quorum votes bps * Must be lower than `MAX_QUORUM_VOTES_BPS_UPPER_BOUND` * Must be higher than or equal to minQuorumVotesBPS */ function _setMaxQuorumVotesBPS(uint16 newMaxQuorumVotesBPS) external { if (msg.sender != admin) { revert AdminOnly(); } DynamicQuorumParams memory params = getDynamicQuorumParamsAt(block.number); require( newMaxQuorumVotesBPS <= MAX_QUORUM_VOTES_BPS_UPPER_BOUND, 'NounsDAO::_setMaxQuorumVotesBPS: invalid max quorum votes bps' ); require( params.minQuorumVotesBPS <= newMaxQuorumVotesBPS, 'NounsDAO::_setMaxQuorumVotesBPS: min quorum votes bps greater than max' ); uint16 oldMaxQuorumVotesBPS = params.maxQuorumVotesBPS; params.maxQuorumVotesBPS = newMaxQuorumVotesBPS; _writeQuorumParamsCheckpoint(params); emit MaxQuorumVotesBPSSet(oldMaxQuorumVotesBPS, newMaxQuorumVotesBPS); } /** * @notice Admin function for setting the dynamic quorum coefficient * @param newQuorumCoefficient the new coefficient, as a fixed point integer with 6 decimals */ function _setQuorumCoefficient(uint32 newQuorumCoefficient) external { if (msg.sender != admin) { revert AdminOnly(); } DynamicQuorumParams memory params = getDynamicQuorumParamsAt(block.number); uint32 oldQuorumCoefficient = params.quorumCoefficient; params.quorumCoefficient = newQuorumCoefficient; _writeQuorumParamsCheckpoint(params); emit QuorumCoefficientSet(oldQuorumCoefficient, newQuorumCoefficient); } /** * @notice Admin function for setting all the dynamic quorum parameters * @param newMinQuorumVotesBPS minimum quorum votes bps * Must be between `MIN_QUORUM_VOTES_BPS_LOWER_BOUND` and `MIN_QUORUM_VOTES_BPS_UPPER_BOUND` * Must be lower than or equal to maxQuorumVotesBPS * @param newMaxQuorumVotesBPS maximum quorum votes bps * Must be lower than `MAX_QUORUM_VOTES_BPS_UPPER_BOUND` * Must be higher than or equal to minQuorumVotesBPS * @param newQuorumCoefficient the new coefficient, as a fixed point integer with 6 decimals */ function _setDynamicQuorumParams( uint16 newMinQuorumVotesBPS, uint16 newMaxQuorumVotesBPS, uint32 newQuorumCoefficient ) public { if (msg.sender != admin) { revert AdminOnly(); } if ( newMinQuorumVotesBPS < MIN_QUORUM_VOTES_BPS_LOWER_BOUND || newMinQuorumVotesBPS > MIN_QUORUM_VOTES_BPS_UPPER_BOUND ) { revert InvalidMinQuorumVotesBPS(); } if (newMaxQuorumVotesBPS > MAX_QUORUM_VOTES_BPS_UPPER_BOUND) { revert InvalidMaxQuorumVotesBPS(); } if (newMinQuorumVotesBPS > newMaxQuorumVotesBPS) { revert MinQuorumBPSGreaterThanMaxQuorumBPS(); } DynamicQuorumParams memory oldParams = getDynamicQuorumParamsAt(block.number); DynamicQuorumParams memory params = DynamicQuorumParams({ minQuorumVotesBPS: newMinQuorumVotesBPS, maxQuorumVotesBPS: newMaxQuorumVotesBPS, quorumCoefficient: newQuorumCoefficient }); _writeQuorumParamsCheckpoint(params); emit MinQuorumVotesBPSSet(oldParams.minQuorumVotesBPS, params.minQuorumVotesBPS); emit MaxQuorumVotesBPSSet(oldParams.maxQuorumVotesBPS, params.maxQuorumVotesBPS); emit QuorumCoefficientSet(oldParams.quorumCoefficient, params.quorumCoefficient); } function _withdraw() external returns (uint256, bool) { if (msg.sender != admin) { revert AdminOnly(); } uint256 amount = address(this).balance; (bool sent, ) = msg.sender.call{ value: amount }(''); emit Withdraw(amount, sent); return (amount, sent); } /** * @notice Begins transfer of admin rights. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer. * @dev Admin function to begin change of admin. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer. * @param newPendingAdmin New pending admin. */ function _setPendingAdmin(address newPendingAdmin) external { // Check caller = admin require(msg.sender == admin, 'NounsDAO::_setPendingAdmin: admin only'); // Save current value, if any, for inclusion in log address oldPendingAdmin = pendingAdmin; // Store pendingAdmin with value newPendingAdmin pendingAdmin = newPendingAdmin; // Emit NewPendingAdmin(oldPendingAdmin, newPendingAdmin) emit NewPendingAdmin(oldPendingAdmin, newPendingAdmin); } /** * @notice Accepts transfer of admin rights. msg.sender must be pendingAdmin * @dev Admin function for pending admin to accept role and update admin */ function _acceptAdmin() external { // Check caller is pendingAdmin and pendingAdmin ≠ address(0) require(msg.sender == pendingAdmin && msg.sender != address(0), 'NounsDAO::_acceptAdmin: pending admin only'); // Save current values for inclusion in log address oldAdmin = admin; address oldPendingAdmin = pendingAdmin; // Store admin with value pendingAdmin admin = pendingAdmin; // Clear the pending value pendingAdmin = address(0); emit NewAdmin(oldAdmin, admin); emit NewPendingAdmin(oldPendingAdmin, pendingAdmin); } /** * @notice Begins transition of vetoer. The newPendingVetoer must call _acceptVetoer to finalize the transfer. * @param newPendingVetoer New Pending Vetoer */ function _setPendingVetoer(address newPendingVetoer) public { if (msg.sender != vetoer) { revert VetoerOnly(); } emit NewPendingVetoer(pendingVetoer, newPendingVetoer); pendingVetoer = newPendingVetoer; } function _acceptVetoer() external { if (msg.sender != pendingVetoer) { revert PendingVetoerOnly(); } // Update vetoer emit NewVetoer(vetoer, pendingVetoer); vetoer = pendingVetoer; // Clear the pending value emit NewPendingVetoer(pendingVetoer, address(0)); pendingVetoer = address(0); } /** * @notice Burns veto priviledges * @dev Vetoer function destroying veto power forever */ function _burnVetoPower() public { // Check caller is vetoer require(msg.sender == vetoer, 'NounsDAO::_burnVetoPower: vetoer only'); // Update vetoer to 0x0 emit NewVetoer(vetoer, address(0)); vetoer = address(0); // Clear the pending value emit NewPendingVetoer(pendingVetoer, address(0)); pendingVetoer = address(0); } /** * @notice Current proposal threshold using Noun Total Supply * Differs from `GovernerBravo` which uses fixed amount */ function proposalThreshold() public view returns (uint256) { return bps2Uint(proposalThresholdBPS, nouns.totalSupply()); } function proposalCreationBlock(Proposal storage proposal) internal view returns (uint256) { if (proposal.creationBlock == 0) { return proposal.startBlock - votingDelay; } return proposal.creationBlock; } /** * @notice Quorum votes required for a specific proposal to succeed * Differs from `GovernerBravo` which uses fixed amount */ function quorumVotes(uint256 proposalId) public view returns (uint256) { Proposal storage proposal = _proposals[proposalId]; if (proposal.totalSupply == 0) { return proposal.quorumVotes; } return dynamicQuorumVotes( proposal.againstVotes, proposal.totalSupply, getDynamicQuorumParamsAt(proposal.creationBlock) ); } /** * @notice Calculates the required quorum of for-votes based on the amount of against-votes * The more against-votes there are for a proposal, the higher the required quorum is. * The quorum BPS is between `params.minQuorumVotesBPS` and params.maxQuorumVotesBPS. * The additional quorum is calculated as: * quorumCoefficient * againstVotesBPS * @dev Note the coefficient is a fixed point integer with 6 decimals * @param againstVotes Number of against-votes in the proposal * @param totalSupply The total supply of Nouns at the time of proposal creation * @param params Configurable parameters for calculating the quorum based on againstVotes. See `DynamicQuorumParams` definition for additional details. * @return quorumVotes The required quorum */ function dynamicQuorumVotes( uint256 againstVotes, uint256 totalSupply, DynamicQuorumParams memory params ) public pure returns (uint256) { uint256 againstVotesBPS = (10000 * againstVotes) / totalSupply; uint256 quorumAdjustmentBPS = (params.quorumCoefficient * againstVotesBPS) / 1e6; uint256 adjustedQuorumBPS = params.minQuorumVotesBPS + quorumAdjustmentBPS; uint256 quorumBPS = min(params.maxQuorumVotesBPS, adjustedQuorumBPS); return bps2Uint(quorumBPS, totalSupply); } /** * @notice returns the dynamic quorum parameters values at a certain block number * @dev The checkpoints array must not be empty, and the block number must be higher than or equal to * the block of the first checkpoint * @param blockNumber_ the block number to get the params at * @return The dynamic quorum parameters that were set at the given block number */ function getDynamicQuorumParamsAt(uint256 blockNumber_) public view returns (DynamicQuorumParams memory) { uint32 blockNumber = safe32(blockNumber_, 'NounsDAO::getDynamicQuorumParamsAt: block number exceeds 32 bits'); uint256 len = quorumParamsCheckpoints.length; if (len == 0) { return DynamicQuorumParams({ minQuorumVotesBPS: safe16(quorumVotesBPS), maxQuorumVotesBPS: safe16(quorumVotesBPS), quorumCoefficient: 0 }); } if (quorumParamsCheckpoints[len - 1].fromBlock <= blockNumber) { return quorumParamsCheckpoints[len - 1].params; } if (quorumParamsCheckpoints[0].fromBlock > blockNumber) { return DynamicQuorumParams({ minQuorumVotesBPS: safe16(quorumVotesBPS), maxQuorumVotesBPS: safe16(quorumVotesBPS), quorumCoefficient: 0 }); } uint256 lower = 0; uint256 upper = len - 1; while (upper > lower) { uint256 center = upper - (upper - lower) / 2; DynamicQuorumParamsCheckpoint memory cp = quorumParamsCheckpoints[center]; if (cp.fromBlock == blockNumber) { return cp.params; } else if (cp.fromBlock < blockNumber) { lower = center; } else { upper = center - 1; } } return quorumParamsCheckpoints[lower].params; } function _writeQuorumParamsCheckpoint(DynamicQuorumParams memory params) internal { uint32 blockNumber = safe32(block.number, 'block number exceeds 32 bits'); uint256 pos = quorumParamsCheckpoints.length; if (pos > 0 && quorumParamsCheckpoints[pos - 1].fromBlock == blockNumber) { quorumParamsCheckpoints[pos - 1].params = params; } else { quorumParamsCheckpoints.push(DynamicQuorumParamsCheckpoint({ fromBlock: blockNumber, params: params })); } } function _refundGas(uint256 startGas) internal { unchecked { uint256 balance = address(this).balance; if (balance == 0) { return; } uint256 basefee = min(block.basefee, MAX_REFUND_BASE_FEE); uint256 gasPrice = min(tx.gasprice, basefee + MAX_REFUND_PRIORITY_FEE); uint256 gasUsed = min(startGas - gasleft() + REFUND_BASE_GAS, MAX_REFUND_GAS_USED); uint256 refundAmount = min(gasPrice * gasUsed, balance); (bool refundSent, ) = tx.origin.call{ value: refundAmount }(''); emit RefundableVote(tx.origin, refundAmount, refundSent); } } function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } /** * @notice Current min quorum votes using Noun total supply */ function minQuorumVotes() public view returns (uint256) { return bps2Uint(getDynamicQuorumParamsAt(block.number).minQuorumVotesBPS, nouns.totalSupply()); } /** * @notice Current max quorum votes using Noun total supply */ function maxQuorumVotes() public view returns (uint256) { return bps2Uint(getDynamicQuorumParamsAt(block.number).maxQuorumVotesBPS, nouns.totalSupply()); } function bps2Uint(uint256 bps, uint256 number) internal pure returns (uint256) { return (number * bps) / 10000; } function getChainIdInternal() internal view returns (uint256) { uint256 chainId; assembly { chainId := chainid() } return chainId; } function safe32(uint256 n, string memory errorMessage) internal pure returns (uint32) { require(n <= type(uint32).max, errorMessage); return uint32(n); } function safe16(uint256 n) internal pure returns (uint16) { if (n > type(uint16).max) { revert UnsafeUint16Cast(); } return uint16(n); } receive() external payable {} }
// SPDX-License-Identifier: BSD-3-Clause /// @title Nouns DAO Logic interfaces and events /********************************* * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ * * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ * * ░░░░░░█████████░░█████████░░░ * * ░░░░░░██░░░████░░██░░░████░░░ * * ░░██████░░░████████░░░████░░░ * * ░░██░░██░░░████░░██░░░████░░░ * * ░░██░░██░░░████░░██░░░████░░░ * * ░░░░░░█████████░░█████████░░░ * * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ * * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ * *********************************/ // LICENSE // NounsDAOInterfaces.sol is a modified version of Compound Lab's GovernorBravoInterfaces.sol: // https://github.com/compound-finance/compound-protocol/blob/b9b14038612d846b83f8a009a82c38974ff2dcfe/contracts/Governance/GovernorBravoInterfaces.sol // // GovernorBravoInterfaces.sol source code Copyright 2020 Compound Labs, Inc. licensed under the BSD-3-Clause license. // With modifications by Nounders DAO. // // Additional conditions of BSD-3-Clause can be found here: https://opensource.org/licenses/BSD-3-Clause // // MODIFICATIONS // NounsDAOEvents, NounsDAOProxyStorage, NounsDAOStorageV1 add support for changes made by Nouns DAO to GovernorBravo.sol // See NounsDAOLogicV1.sol for more details. // NounsDAOStorageV1Adjusted and NounsDAOStorageV2 add support for a dynamic vote quorum. // See NounsDAOLogicV2.sol for more details. pragma solidity ^0.8.6; contract NounsDAOEvents { /// @notice An event emitted when a new proposal is created event ProposalCreated( uint256 id, address proposer, address[] targets, uint256[] values, string[] signatures, bytes[] calldatas, uint256 startBlock, uint256 endBlock, string description ); /// @notice An event emitted when a new proposal is created, which includes additional information event ProposalCreatedWithRequirements( uint256 id, address proposer, address[] targets, uint256[] values, string[] signatures, bytes[] calldatas, uint256 startBlock, uint256 endBlock, uint256 proposalThreshold, uint256 quorumVotes, string description ); /// @notice An event emitted when a vote has been cast on a proposal /// @param voter The address which casted a vote /// @param proposalId The proposal id which was voted on /// @param support Support value for the vote. 0=against, 1=for, 2=abstain /// @param votes Number of votes which were cast by the voter /// @param reason The reason given for the vote by the voter event VoteCast(address indexed voter, uint256 proposalId, uint8 support, uint256 votes, string reason); /// @notice An event emitted when a proposal has been canceled event ProposalCanceled(uint256 id); /// @notice An event emitted when a proposal has been queued in the NounsDAOExecutor event ProposalQueued(uint256 id, uint256 eta); /// @notice An event emitted when a proposal has been executed in the NounsDAOExecutor event ProposalExecuted(uint256 id); /// @notice An event emitted when a proposal has been vetoed by vetoAddress event ProposalVetoed(uint256 id); /// @notice An event emitted when the voting delay is set event VotingDelaySet(uint256 oldVotingDelay, uint256 newVotingDelay); /// @notice An event emitted when the voting period is set event VotingPeriodSet(uint256 oldVotingPeriod, uint256 newVotingPeriod); /// @notice Emitted when implementation is changed event NewImplementation(address oldImplementation, address newImplementation); /// @notice Emitted when proposal threshold basis points is set event ProposalThresholdBPSSet(uint256 oldProposalThresholdBPS, uint256 newProposalThresholdBPS); /// @notice Emitted when quorum votes basis points is set event QuorumVotesBPSSet(uint256 oldQuorumVotesBPS, uint256 newQuorumVotesBPS); /// @notice Emitted when pendingAdmin is changed event NewPendingAdmin(address oldPendingAdmin, address newPendingAdmin); /// @notice Emitted when pendingAdmin is accepted, which means admin is updated event NewAdmin(address oldAdmin, address newAdmin); /// @notice Emitted when vetoer is changed event NewVetoer(address oldVetoer, address newVetoer); } contract NounsDAOEventsV2 is NounsDAOEvents { /// @notice Emitted when minQuorumVotesBPS is set event MinQuorumVotesBPSSet(uint16 oldMinQuorumVotesBPS, uint16 newMinQuorumVotesBPS); /// @notice Emitted when maxQuorumVotesBPS is set event MaxQuorumVotesBPSSet(uint16 oldMaxQuorumVotesBPS, uint16 newMaxQuorumVotesBPS); /// @notice Emitted when quorumCoefficient is set event QuorumCoefficientSet(uint32 oldQuorumCoefficient, uint32 newQuorumCoefficient); /// @notice Emitted when a voter cast a vote requesting a gas refund. event RefundableVote(address indexed voter, uint256 refundAmount, bool refundSent); /// @notice Emitted when admin withdraws the DAO's balance. event Withdraw(uint256 amount, bool sent); /// @notice Emitted when pendingVetoer is changed event NewPendingVetoer(address oldPendingVetoer, address newPendingVetoer); } contract NounsDAOProxyStorage { /// @notice Administrator for this contract address public admin; /// @notice Pending administrator for this contract address public pendingAdmin; /// @notice Active brains of Governor address public implementation; } /** * @title Storage for Governor Bravo Delegate * @notice For future upgrades, do not change NounsDAOStorageV1. Create a new * contract which implements NounsDAOStorageV1 and following the naming convention * NounsDAOStorageVX. */ contract NounsDAOStorageV1 is NounsDAOProxyStorage { /// @notice Vetoer who has the ability to veto any proposal address public vetoer; /// @notice The delay before voting on a proposal may take place, once proposed, in blocks uint256 public votingDelay; /// @notice The duration of voting on a proposal, in blocks uint256 public votingPeriod; /// @notice The basis point number of votes required in order for a voter to become a proposer. *DIFFERS from GovernerBravo uint256 public proposalThresholdBPS; /// @notice The basis point number of votes in support of a proposal required in order for a quorum to be reached and for a vote to succeed. *DIFFERS from GovernerBravo uint256 public quorumVotesBPS; /// @notice The total number of proposals uint256 public proposalCount; /// @notice The address of the Nouns DAO Executor NounsDAOExecutor INounsDAOExecutor public timelock; /// @notice The address of the Nouns tokens NounsTokenLike public nouns; /// @notice The official record of all proposals ever proposed mapping(uint256 => Proposal) public proposals; /// @notice The latest proposal for each proposer mapping(address => uint256) public latestProposalIds; struct Proposal { /// @notice Unique id for looking up a proposal uint256 id; /// @notice Creator of the proposal address proposer; /// @notice The number of votes needed to create a proposal at the time of proposal creation. *DIFFERS from GovernerBravo uint256 proposalThreshold; /// @notice The number of votes in support of a proposal required in order for a quorum to be reached and for a vote to succeed at the time of proposal creation. *DIFFERS from GovernerBravo uint256 quorumVotes; /// @notice The timestamp that the proposal will be available for execution, set once the vote succeeds uint256 eta; /// @notice the ordered list of target addresses for calls to be made address[] targets; /// @notice The ordered list of values (i.e. msg.value) to be passed to the calls to be made uint256[] values; /// @notice The ordered list of function signatures to be called string[] signatures; /// @notice The ordered list of calldata to be passed to each call bytes[] calldatas; /// @notice The block at which voting begins: holders must delegate their votes prior to this block uint256 startBlock; /// @notice The block at which voting ends: votes must be cast prior to this block uint256 endBlock; /// @notice Current number of votes in favor of this proposal uint256 forVotes; /// @notice Current number of votes in opposition to this proposal uint256 againstVotes; /// @notice Current number of votes for abstaining for this proposal uint256 abstainVotes; /// @notice Flag marking whether the proposal has been canceled bool canceled; /// @notice Flag marking whether the proposal has been vetoed bool vetoed; /// @notice Flag marking whether the proposal has been executed bool executed; /// @notice Receipts of ballots for the entire set of voters mapping(address => Receipt) receipts; } /// @notice Ballot receipt record for a voter struct Receipt { /// @notice Whether or not a vote has been cast bool hasVoted; /// @notice Whether or not the voter supports the proposal or abstains uint8 support; /// @notice The number of votes the voter had, which were cast uint96 votes; } /// @notice Possible states that a proposal may be in enum ProposalState { Pending, Active, Canceled, Defeated, Succeeded, Queued, Expired, Executed, Vetoed } } /** * @title Extra fields added to the `Proposal` struct from NounsDAOStorageV1 * @notice The following fields were added to the `Proposal` struct: * - `Proposal.totalSupply` * - `Proposal.creationBlock` */ contract NounsDAOStorageV1Adjusted is NounsDAOProxyStorage { /// @notice Vetoer who has the ability to veto any proposal address public vetoer; /// @notice The delay before voting on a proposal may take place, once proposed, in blocks uint256 public votingDelay; /// @notice The duration of voting on a proposal, in blocks uint256 public votingPeriod; /// @notice The basis point number of votes required in order for a voter to become a proposer. *DIFFERS from GovernerBravo uint256 public proposalThresholdBPS; /// @notice The basis point number of votes in support of a proposal required in order for a quorum to be reached and for a vote to succeed. *DIFFERS from GovernerBravo uint256 public quorumVotesBPS; /// @notice The total number of proposals uint256 public proposalCount; /// @notice The address of the Nouns DAO Executor NounsDAOExecutor INounsDAOExecutor public timelock; /// @notice The address of the Nouns tokens NounsTokenLike public nouns; /// @notice The official record of all proposals ever proposed mapping(uint256 => Proposal) internal _proposals; /// @notice The latest proposal for each proposer mapping(address => uint256) public latestProposalIds; struct Proposal { /// @notice Unique id for looking up a proposal uint256 id; /// @notice Creator of the proposal address proposer; /// @notice The number of votes needed to create a proposal at the time of proposal creation. *DIFFERS from GovernerBravo uint256 proposalThreshold; /// @notice The number of votes in support of a proposal required in order for a quorum to be reached and for a vote to succeed at the time of proposal creation. *DIFFERS from GovernerBravo uint256 quorumVotes; /// @notice The timestamp that the proposal will be available for execution, set once the vote succeeds uint256 eta; /// @notice the ordered list of target addresses for calls to be made address[] targets; /// @notice The ordered list of values (i.e. msg.value) to be passed to the calls to be made uint256[] values; /// @notice The ordered list of function signatures to be called string[] signatures; /// @notice The ordered list of calldata to be passed to each call bytes[] calldatas; /// @notice The block at which voting begins: holders must delegate their votes prior to this block uint256 startBlock; /// @notice The block at which voting ends: votes must be cast prior to this block uint256 endBlock; /// @notice Current number of votes in favor of this proposal uint256 forVotes; /// @notice Current number of votes in opposition to this proposal uint256 againstVotes; /// @notice Current number of votes for abstaining for this proposal uint256 abstainVotes; /// @notice Flag marking whether the proposal has been canceled bool canceled; /// @notice Flag marking whether the proposal has been vetoed bool vetoed; /// @notice Flag marking whether the proposal has been executed bool executed; /// @notice Receipts of ballots for the entire set of voters mapping(address => Receipt) receipts; /// @notice The total supply at the time of proposal creation uint256 totalSupply; /// @notice The block at which this proposal was created uint256 creationBlock; } /// @notice Ballot receipt record for a voter struct Receipt { /// @notice Whether or not a vote has been cast bool hasVoted; /// @notice Whether or not the voter supports the proposal or abstains uint8 support; /// @notice The number of votes the voter had, which were cast uint96 votes; } /// @notice Possible states that a proposal may be in enum ProposalState { Pending, Active, Canceled, Defeated, Succeeded, Queued, Expired, Executed, Vetoed } } /** * @title Storage for Governor Bravo Delegate * @notice For future upgrades, do not change NounsDAOStorageV2. Create a new * contract which implements NounsDAOStorageV2 and following the naming convention * NounsDAOStorageVX. */ contract NounsDAOStorageV2 is NounsDAOStorageV1Adjusted { DynamicQuorumParamsCheckpoint[] public quorumParamsCheckpoints; /// @notice Pending new vetoer address public pendingVetoer; struct DynamicQuorumParams { /// @notice The minimum basis point number of votes in support of a proposal required in order for a quorum to be reached and for a vote to succeed. uint16 minQuorumVotesBPS; /// @notice The maximum basis point number of votes in support of a proposal required in order for a quorum to be reached and for a vote to succeed. uint16 maxQuorumVotesBPS; /// @notice The dynamic quorum coefficient /// @dev Assumed to be fixed point integer with 6 decimals, i.e 0.2 is represented as 0.2 * 1e6 = 200000 uint32 quorumCoefficient; } /// @notice A checkpoint for storing dynamic quorum params from a given block struct DynamicQuorumParamsCheckpoint { /// @notice The block at which the new values were set uint32 fromBlock; /// @notice The parameter values of this checkpoint DynamicQuorumParams params; } struct ProposalCondensed { /// @notice Unique id for looking up a proposal uint256 id; /// @notice Creator of the proposal address proposer; /// @notice The number of votes needed to create a proposal at the time of proposal creation. *DIFFERS from GovernerBravo uint256 proposalThreshold; /// @notice The minimum number of votes in support of a proposal required in order for a quorum to be reached and for a vote to succeed at the time of proposal creation. *DIFFERS from GovernerBravo uint256 quorumVotes; /// @notice The timestamp that the proposal will be available for execution, set once the vote succeeds uint256 eta; /// @notice The block at which voting begins: holders must delegate their votes prior to this block uint256 startBlock; /// @notice The block at which voting ends: votes must be cast prior to this block uint256 endBlock; /// @notice Current number of votes in favor of this proposal uint256 forVotes; /// @notice Current number of votes in opposition to this proposal uint256 againstVotes; /// @notice Current number of votes for abstaining for this proposal uint256 abstainVotes; /// @notice Flag marking whether the proposal has been canceled bool canceled; /// @notice Flag marking whether the proposal has been vetoed bool vetoed; /// @notice Flag marking whether the proposal has been executed bool executed; /// @notice The total supply at the time of proposal creation uint256 totalSupply; /// @notice The block at which this proposal was created uint256 creationBlock; } } interface INounsDAOExecutor { function delay() external view returns (uint256); function GRACE_PERIOD() external view returns (uint256); function acceptAdmin() external; function queuedTransactions(bytes32 hash) external view returns (bool); function queueTransaction( address target, uint256 value, string calldata signature, bytes calldata data, uint256 eta ) external returns (bytes32); function cancelTransaction( address target, uint256 value, string calldata signature, bytes calldata data, uint256 eta ) external; function executeTransaction( address target, uint256 value, string calldata signature, bytes calldata data, uint256 eta ) external payable returns (bytes memory); } interface NounsTokenLike { function getPriorVotes(address account, uint256 blockNumber) external view returns (uint96); function totalSupply() external view returns (uint256); }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.0; library GasRefund { /// @notice The maximum priority fee used to cap gas refunds in `castRefundableVote` uint256 public constant MAX_REFUND_PRIORITY_FEE = 2 gwei; /// @notice The vote refund gas overhead, including 7K for ETH transfer and 29K for general transaction overhead uint256 public constant REFUND_BASE_GAS = 36000; /// @notice The maximum gas units the DAO will refund voters on; supports about 9,190 characters uint256 public constant MAX_REFUND_GAS_USED = 200_000; /// @notice The maximum basefee the DAO will refund voters on uint256 public constant MAX_REFUND_BASE_FEE = 200 gwei; // modified, from https://github.com/nounsDAO/nouns-monorepo/blob/master/packages/nouns-contracts/contracts/governance/NounsDAOLogicV2.sol#LL1033C4-L1033C4 function refundGas(uint256 startGas) internal { unchecked { uint256 balance = address(this).balance; if (balance == 0) { return; } uint256 basefee = min(block.basefee, MAX_REFUND_BASE_FEE); uint256 gasPrice = min(tx.gasprice, basefee + MAX_REFUND_PRIORITY_FEE); uint256 gasUsed = min(startGas - gasleft() + REFUND_BASE_GAS, MAX_REFUND_GAS_USED); uint256 refundAmount = min(gasPrice * gasUsed, balance); // we do not care if this reverts // gas account is already done and update posted tx.origin.call{value: refundAmount}(""); } } function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } }
{ "remappings": [ "ds-test/=lib/forge-std/lib/ds-test/src/", "forge-std/=lib/forge-std/src/", "nouns-monorepo/=lib/nouns-monorepo/" ], "optimizer": { "enabled": true, "runs": 200 }, "metadata": { "bytecodeHash": "ipfs" }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "evmVersion": "london", "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[],"name":"NoZeroAddress","type":"error"},{"inputs":[],"name":"OnlyPendingPropUpdateAdmin","type":"error"},{"inputs":[],"name":"OnlyPropUpdateAdmin","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"propId","type":"uint256"},{"indexed":true,"internalType":"bool","name":"isCompleted","type":"bool"},{"indexed":false,"internalType":"string","name":"update","type":"string"}],"name":"PostUpdate","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"propId","type":"uint256"},{"indexed":true,"internalType":"address","name":"oldAdmin","type":"address"},{"indexed":true,"internalType":"address","name":"newAdmin","type":"address"}],"name":"PropUpdateAdminTransferStarted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"propId","type":"uint256"},{"indexed":true,"internalType":"address","name":"oldAdmin","type":"address"},{"indexed":true,"internalType":"address","name":"newAdmin","type":"address"}],"name":"PropUpdateAdminTransfered","type":"event"},{"inputs":[],"name":"NOUNS_DAO","outputs":[{"internalType":"address payable","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"propId","type":"uint256"}],"name":"acceptPropUpdateAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"pendingPropUpdateAdmin","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"propId","type":"uint256"},{"internalType":"bool","name":"isCompleted","type":"bool"},{"internalType":"string","name":"update","type":"string"}],"name":"postUpdate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"propId","type":"uint256"}],"name":"propdateInfo","outputs":[{"components":[{"internalType":"address","name":"propUpdateAdmin","type":"address"},{"internalType":"uint88","name":"lastUpdated","type":"uint88"},{"internalType":"bool","name":"isCompleted","type":"bool"}],"internalType":"struct Propdates.PropdateInfo","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"propId","type":"uint256"},{"internalType":"address","name":"newAdmin","type":"address"}],"name":"transferPropUpdateAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]
Contract Creation Code
608060405234801561001057600080fd5b506108f1806100206000396000f3fe6080604052600436106100595760003560e01c80630634e5b3146100655780632b260328146100b85780634156445f146100da57806348becb6e146101025780634e252fe4146101c2578063e65fe7c6146101e257600080fd5b3661006057005b600080fd5b34801561007157600080fd5b5061009b61008036600461066b565b6000602081905290815260409020546001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b3480156100c457600080fd5b506100d86100d3366004610699565b610202565b005b3480156100e657600080fd5b5061009b736f3e6272a167e8accb32072d08e0957f9c79223d81565b34801561010e57600080fd5b5061018861011d36600461066b565b604080516060808201835260008083526020808401829052928401819052938452600182529282902082519384018352546001600160a01b0381168452600160a01b81046affffffffffffffffffffff1691840191909152600160f81b900460ff1615159082015290565b6040805182516001600160a01b031681526020808401516affffffffffffffffffffff1690820152918101511515908201526060016100af565b3480156101ce57600080fd5b506100d86101dd36600461066b565b610362565b3480156101ee57600080fd5b506100d86101fd3660046106d7565b6103a5565b6001600160a01b0381166102295760405163ddbadd5f60e01b815260040160405180910390fd5b6000828152600160205260409020546001600160a01b03163381148015906102e657506001600160a01b0381161580156102e4575060405163013cf08b60e01b8152600481018490523390736f3e6272a167e8accb32072d08e0957f9c79223d9063013cf08b906024016101e060405180830381865afa1580156102b1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102d591906107b3565b602001516001600160a01b0316145b155b1561030457604051639fef201760e01b815260040160405180910390fd5b60008381526020819052604080822080546001600160a01b0319166001600160a01b03868116918217909255915191929084169186917ff2435ad1a812d3d71454d447f6cfbf85b5aa5826d8fb1f5cf32fcf0cfbdd6bba91a4505050565b6000818152602081905260409020546001600160a01b0316331461039957604051633854e8f760e21b815260040160405180910390fd5b6103a28161053a565b50565b60005a6000868152600160205260409020549091506001600160a01b0316331461040e576000858152602081905260409020546001600160a01b031633036103f5576103f08561053a565b61040e565b604051639fef201760e01b815260040160405180910390fd5b600085815260016020526040902080546affffffffffffffffffffff60a01b1916600160a01b426affffffffffffffffffffff1602179055831561046e57600085815260016020526040902080546001600160f81b0316600160f81b1790555b831515857fcbeea0cc82b02b8b2687b661a00b2beefee33d74a34bcfb9f364ff2017d0071185856040516104a392919061088c565b60405180910390a360405163013cf08b60e01b815260048101869052736f3e6272a167e8accb32072d08e0957f9c79223d9063013cf08b906024016101e060405180830381865afa1580156104fc573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061052091906107b3565b61018001511561053357610533816105a6565b5050505050565b60008181526020818152604080832080546001600160a01b03199081169091556001909252808320805433938116841790915590516001600160a01b0390911692839185917fd16ea0c342dd387701114ee92785a5556bb46815ba9e457d298bc6c23edcc79191a45050565b4760008190036105b4575050565b60006105c548642e90edd000610653565b905060006105d93a63773594008401610653565b905060006105f0618ca05a87030162030d40610653565b9050600061060082840286610653565b60405190915032908290600081818185875af1925050503d8060008114610643576040519150601f19603f3d011682016040523d82523d6000602084013e610648565b606091505b505050505050505050565b60008183106106625781610664565b825b9392505050565b60006020828403121561067d57600080fd5b5035919050565b6001600160a01b03811681146103a257600080fd5b600080604083850312156106ac57600080fd5b8235915060208301356106be81610684565b809150509250929050565b80151581146103a257600080fd5b600080600080606085870312156106ed57600080fd5b8435935060208501356106ff816106c9565b9250604085013567ffffffffffffffff8082111561071c57600080fd5b818701915087601f83011261073057600080fd5b81358181111561073f57600080fd5b88602082850101111561075157600080fd5b95989497505060200194505050565b6040516101e0810167ffffffffffffffff8111828210171561079257634e487b7160e01b600052604160045260246000fd5b60405290565b80516107a381610684565b919050565b80516107a3816106c9565b60006101e082840312156107c657600080fd5b6107ce610760565b825181526107de60208401610798565b602082015260408301516040820152606083015160608201526080830151608082015260a083015160a082015260c083015160c082015260e083015160e08201526101008084015181830152506101208084015181830152506101406108458185016107a8565b908201526101606108578482016107a8565b908201526101806108698482016107a8565b908201526101a083810151908201526101c0928301519281019290925250919050565b60208152816020820152818360408301376000818301604090810191909152601f909201601f1916010191905056fea26469706673582212201bb6b874144d048d81b9beb70ae9b60e338ef8ef08cc5608729c72dcb9c1490564736f6c63430008110033
Deployed Bytecode
0x6080604052600436106100595760003560e01c80630634e5b3146100655780632b260328146100b85780634156445f146100da57806348becb6e146101025780634e252fe4146101c2578063e65fe7c6146101e257600080fd5b3661006057005b600080fd5b34801561007157600080fd5b5061009b61008036600461066b565b6000602081905290815260409020546001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b3480156100c457600080fd5b506100d86100d3366004610699565b610202565b005b3480156100e657600080fd5b5061009b736f3e6272a167e8accb32072d08e0957f9c79223d81565b34801561010e57600080fd5b5061018861011d36600461066b565b604080516060808201835260008083526020808401829052928401819052938452600182529282902082519384018352546001600160a01b0381168452600160a01b81046affffffffffffffffffffff1691840191909152600160f81b900460ff1615159082015290565b6040805182516001600160a01b031681526020808401516affffffffffffffffffffff1690820152918101511515908201526060016100af565b3480156101ce57600080fd5b506100d86101dd36600461066b565b610362565b3480156101ee57600080fd5b506100d86101fd3660046106d7565b6103a5565b6001600160a01b0381166102295760405163ddbadd5f60e01b815260040160405180910390fd5b6000828152600160205260409020546001600160a01b03163381148015906102e657506001600160a01b0381161580156102e4575060405163013cf08b60e01b8152600481018490523390736f3e6272a167e8accb32072d08e0957f9c79223d9063013cf08b906024016101e060405180830381865afa1580156102b1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102d591906107b3565b602001516001600160a01b0316145b155b1561030457604051639fef201760e01b815260040160405180910390fd5b60008381526020819052604080822080546001600160a01b0319166001600160a01b03868116918217909255915191929084169186917ff2435ad1a812d3d71454d447f6cfbf85b5aa5826d8fb1f5cf32fcf0cfbdd6bba91a4505050565b6000818152602081905260409020546001600160a01b0316331461039957604051633854e8f760e21b815260040160405180910390fd5b6103a28161053a565b50565b60005a6000868152600160205260409020549091506001600160a01b0316331461040e576000858152602081905260409020546001600160a01b031633036103f5576103f08561053a565b61040e565b604051639fef201760e01b815260040160405180910390fd5b600085815260016020526040902080546affffffffffffffffffffff60a01b1916600160a01b426affffffffffffffffffffff1602179055831561046e57600085815260016020526040902080546001600160f81b0316600160f81b1790555b831515857fcbeea0cc82b02b8b2687b661a00b2beefee33d74a34bcfb9f364ff2017d0071185856040516104a392919061088c565b60405180910390a360405163013cf08b60e01b815260048101869052736f3e6272a167e8accb32072d08e0957f9c79223d9063013cf08b906024016101e060405180830381865afa1580156104fc573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061052091906107b3565b61018001511561053357610533816105a6565b5050505050565b60008181526020818152604080832080546001600160a01b03199081169091556001909252808320805433938116841790915590516001600160a01b0390911692839185917fd16ea0c342dd387701114ee92785a5556bb46815ba9e457d298bc6c23edcc79191a45050565b4760008190036105b4575050565b60006105c548642e90edd000610653565b905060006105d93a63773594008401610653565b905060006105f0618ca05a87030162030d40610653565b9050600061060082840286610653565b60405190915032908290600081818185875af1925050503d8060008114610643576040519150601f19603f3d011682016040523d82523d6000602084013e610648565b606091505b505050505050505050565b60008183106106625781610664565b825b9392505050565b60006020828403121561067d57600080fd5b5035919050565b6001600160a01b03811681146103a257600080fd5b600080604083850312156106ac57600080fd5b8235915060208301356106be81610684565b809150509250929050565b80151581146103a257600080fd5b600080600080606085870312156106ed57600080fd5b8435935060208501356106ff816106c9565b9250604085013567ffffffffffffffff8082111561071c57600080fd5b818701915087601f83011261073057600080fd5b81358181111561073f57600080fd5b88602082850101111561075157600080fd5b95989497505060200194505050565b6040516101e0810167ffffffffffffffff8111828210171561079257634e487b7160e01b600052604160045260246000fd5b60405290565b80516107a381610684565b919050565b80516107a3816106c9565b60006101e082840312156107c657600080fd5b6107ce610760565b825181526107de60208401610798565b602082015260408301516040820152606083015160608201526080830151608082015260a083015160a082015260c083015160c082015260e083015160e08201526101008084015181830152506101208084015181830152506101406108458185016107a8565b908201526101606108578482016107a8565b908201526101806108698482016107a8565b908201526101a083810151908201526101c0928301519281019290925250919050565b60208152816020820152818360408301376000818301604090810191909152601f909201601f1916010191905056fea26469706673582212201bb6b874144d048d81b9beb70ae9b60e338ef8ef08cc5608729c72dcb9c1490564736f6c63430008110033
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 26 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|---|---|---|---|---|
ETH | 100.00% | $3,300.85 | 0.3123 | $1,030.79 |
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.