diff --git a/.github/workflows/contracts.yaml b/.github/workflows/contracts.yaml index 61aeae3ac1..fab182d081 100644 --- a/.github/workflows/contracts.yaml +++ b/.github/workflows/contracts.yaml @@ -50,4 +50,6 @@ jobs: - name: Run Forge tests run: | cd packages/nouns-contracts - forge test -vvv --ffi --nmc 'MainnetForkTest' + forge test -vvv --ffi + env: + RPC_MAINNET: ${{ secrets.RPC_MAINNET }} diff --git a/packages/nouns-assets/images/noundry/0-backgrounds/.gitkeep b/packages/nouns-assets/images/noundry/0-backgrounds/.gitkeep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/nouns-assets/images/noundry/1-bodies/.gitkeep b/packages/nouns-assets/images/noundry/1-bodies/.gitkeep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/nouns-assets/images/noundry/2-accessories/.gitkeep b/packages/nouns-assets/images/noundry/2-accessories/.gitkeep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/nouns-assets/images/noundry/3-heads/head-tuba.png b/packages/nouns-assets/images/noundry/3-heads/head-tuba.png new file mode 100644 index 0000000000..3b894b4f39 Binary files /dev/null and b/packages/nouns-assets/images/noundry/3-heads/head-tuba.png differ diff --git a/packages/nouns-assets/images/noundry/4-glasses/.gitkeep b/packages/nouns-assets/images/noundry/4-glasses/.gitkeep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/nouns-assets/src/image-data.json b/packages/nouns-assets/src/image-data.json index bc1db7305a..3596aa4096 100644 --- a/packages/nouns-assets/src/image-data.json +++ b/packages/nouns-assets/src/image-data.json @@ -1934,6 +1934,10 @@ { "filename": "head-tiger", "data": "0x000619140804240800032402000424080003240300051501240115012401150124041503000715012406150300021504c1031504c101150300021504c1031504c101150300021504c1031504c101150300021504c1031504c101150300031503c1031503c104150100032403c1031503c104240100031503c1031503c104150100032403c1042402c104240100031503c1042402c104150100032401c1022406c104240100031509c10415" + }, + { + "filename": "head-tuba", + "data": "0x00041b15060b00030513000105070001c20c0001c2060002c20c0001c2050003c203000fc2015e02c2020001c20d5e01c2015e03c2010001c2015e56c2020001c2020001c2040002c2010007c2010008c20105020002c2010005c2010001c2050001c2050002c2020004c2010009c20105020002c2030003c2010001c2050001c2050002c2030004c2010008c20105020002c2040004c2020001c2020001c2040003c205000fc20400" } ], "glasses": [ diff --git a/packages/nouns-contracts/.env.example b/packages/nouns-contracts/.env.example index b273bf22b2..15c08e2f55 100644 --- a/packages/nouns-contracts/.env.example +++ b/packages/nouns-contracts/.env.example @@ -6,3 +6,5 @@ MNEMONIC= # or specify a private key to use a single account WALLET_PUBLIC_KEY= WALLET_PRIVATE_KEY= + +FOUNDRY_PROFILE=lite diff --git a/packages/nouns-contracts/.gas-snapshot b/packages/nouns-contracts/.gas-snapshot index 74f2b93661..9e1685ffc3 100644 --- a/packages/nouns-contracts/.gas-snapshot +++ b/packages/nouns-contracts/.gas-snapshot @@ -1,11 +1,25 @@ -NounsDAOLogic_GasSnapshot_V2_propose:test_propose_longDescription() (gas: 528733) -NounsDAOLogic_GasSnapshot_V2_propose:test_propose_shortDescription() (gas: 398388) -NounsDAOLogic_GasSnapshot_V2_vote:test_castVoteWithReason() (gas: 83474) -NounsDAOLogic_GasSnapshot_V2_vote:test_castVote_against() (gas: 82886) -NounsDAOLogic_GasSnapshot_V2_vote:test_castVote_lastMinuteFor() (gas: 83459) -NounsDAOLogic_GasSnapshot_V3_propose:test_propose_longDescription() (gas: 538195) -NounsDAOLogic_GasSnapshot_V3_propose:test_propose_shortDescription() (gas: 404029) -NounsDAOLogic_GasSnapshot_V3_vote:test_castVoteWithReason() (gas: 89809) -NounsDAOLogic_GasSnapshot_V3_vote:test_castVote_against() (gas: 88733) -NounsDAOLogic_GasSnapshot_V3_vote:test_castVote_lastMinuteFor() (gas: 112249) -NounsDAOLogic_GasSnapshot_V3_voteDuringObjectionPeriod:test_castVote_duringObjectionPeriod_against() (gas: 88656) \ No newline at end of file +NounsAuctionHouseV2WarmedUp_GasSnapshot:test_createOneBid() (gas: 34919) +NounsAuctionHouseV2WarmedUp_GasSnapshot:test_createTwoBids() (gas: 93402) +NounsAuctionHouseV2WarmedUp_GasSnapshot:test_settleCurrentAndCreateNewAuction() (gas: 207740) +NounsAuctionHouseV2_GasSnapshot:test_createOneBid() (gas: 34919) +NounsAuctionHouseV2_GasSnapshot:test_createTwoBids() (gas: 93402) +NounsAuctionHouseV2_GasSnapshot:test_settleCurrentAndCreateNewAuction() (gas: 224840) +NounsAuctionHouseV2_HistoricPrices_GasSnapshot:test_getPrices_90() (gas: 309470) +NounsAuctionHouseV2_HistoricPrices_GasSnapshot:test_getPrices_range_90() (gas: 300032) +NounsAuctionHouseV2_HistoricPrices_GasSnapshot:test_getSettlements_90() (gas: 385146) +NounsAuctionHouseV2_HistoricPrices_GasSnapshot:test_getSettlements_range_90() (gas: 377611) +NounsAuctionHouseV2_HistoricPrices_GasSnapshot:test_warmUp() (gas: 18716940) +NounsAuctionHouse_GasSnapshot:test_createOneBid() (gas: 81452) +NounsAuctionHouse_GasSnapshot:test_createTwoBids() (gas: 142758) +NounsAuctionHouse_GasSnapshot:test_settleCurrentAndCreateNewAuction() (gas: 218092) +NounsDAOLogic_GasSnapshot_V2_propose:test_propose_longDescription() (gas: 528758) +NounsDAOLogic_GasSnapshot_V2_propose:test_propose_shortDescription() (gas: 398372) +NounsDAOLogic_GasSnapshot_V2_vote:test_castVoteWithReason() (gas: 83513) +NounsDAOLogic_GasSnapshot_V2_vote:test_castVote_against() (gas: 82974) +NounsDAOLogic_GasSnapshot_V2_vote:test_castVote_lastMinuteFor() (gas: 83525) +NounsDAOLogic_GasSnapshot_V3_propose:test_propose_longDescription() (gas: 538416) +NounsDAOLogic_GasSnapshot_V3_propose:test_propose_shortDescription() (gas: 404209) +NounsDAOLogic_GasSnapshot_V3_vote:test_castVoteWithReason() (gas: 89810) +NounsDAOLogic_GasSnapshot_V3_vote:test_castVote_against() (gas: 88761) +NounsDAOLogic_GasSnapshot_V3_vote:test_castVote_lastMinuteFor() (gas: 112254) +NounsDAOLogic_GasSnapshot_V3_voteDuringObjectionPeriod:test_castVote_duringObjectionPeriod_against() (gas: 88724) \ No newline at end of file diff --git a/packages/nouns-contracts/abi/contracts/NounsAuctionHouseV2.json b/packages/nouns-contracts/abi/contracts/NounsAuctionHouseV2.json new file mode 100644 index 0000000000..bbc693f987 --- /dev/null +++ b/packages/nouns-contracts/abi/contracts/NounsAuctionHouseV2.json @@ -0,0 +1,851 @@ +[ + { + "inputs": [ + { + "internalType": "contract INounsToken", + "name": "_nouns", + "type": "address" + }, + { + "internalType": "address", + "name": "_weth", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_duration", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "nounId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "value", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "bool", + "name": "extended", + "type": "bool" + } + ], + "name": "AuctionBid", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "nounId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "value", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "uint32", + "name": "clientId", + "type": "uint32" + } + ], + "name": "AuctionBidWithClientId", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "nounId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "startTime", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "endTime", + "type": "uint256" + } + ], + "name": "AuctionCreated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "nounId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "endTime", + "type": "uint256" + } + ], + "name": "AuctionExtended", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "minBidIncrementPercentage", + "type": "uint256" + } + ], + "name": "AuctionMinBidIncrementPercentageUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "reservePrice", + "type": "uint256" + } + ], + "name": "AuctionReservePriceUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "nounId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address", + "name": "winner", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "AuctionSettled", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "nounId", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "uint32", + "name": "clientId", + "type": "uint32" + } + ], + "name": "AuctionSettledWithClientId", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "timeBuffer", + "type": "uint256" + } + ], + "name": "AuctionTimeBufferUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "Paused", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "Unpaused", + "type": "event" + }, + { + "inputs": [], + "name": "MAX_TIME_BUFFER", + "outputs": [ + { + "internalType": "uint56", + "name": "", + "type": "uint56" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "auction", + "outputs": [ + { + "components": [ + { + "internalType": "uint96", + "name": "nounId", + "type": "uint96" + }, + { + "internalType": "uint128", + "name": "amount", + "type": "uint128" + }, + { + "internalType": "uint40", + "name": "startTime", + "type": "uint40" + }, + { + "internalType": "uint40", + "name": "endTime", + "type": "uint40" + }, + { + "internalType": "address payable", + "name": "bidder", + "type": "address" + }, + { + "internalType": "bool", + "name": "settled", + "type": "bool" + } + ], + "internalType": "struct INounsAuctionHouseV2.AuctionV2View", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "auctionStorage", + "outputs": [ + { + "internalType": "uint96", + "name": "nounId", + "type": "uint96" + }, + { + "internalType": "uint32", + "name": "clientId", + "type": "uint32" + }, + { + "internalType": "uint128", + "name": "amount", + "type": "uint128" + }, + { + "internalType": "uint40", + "name": "startTime", + "type": "uint40" + }, + { + "internalType": "uint40", + "name": "endTime", + "type": "uint40" + }, + { + "internalType": "address payable", + "name": "bidder", + "type": "address" + }, + { + "internalType": "bool", + "name": "settled", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "nounId", + "type": "uint256" + } + ], + "name": "biddingClient", + "outputs": [ + { + "internalType": "uint32", + "name": "", + "type": "uint32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "nounId", + "type": "uint256" + } + ], + "name": "createBid", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "nounId", + "type": "uint256" + }, + { + "internalType": "uint32", + "name": "clientId", + "type": "uint32" + } + ], + "name": "createBid", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [], + "name": "duration", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "auctionCount", + "type": "uint256" + } + ], + "name": "getPrices", + "outputs": [ + { + "internalType": "uint256[]", + "name": "prices", + "type": "uint256[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "auctionCount", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "skipEmptyValues", + "type": "bool" + } + ], + "name": "getSettlements", + "outputs": [ + { + "components": [ + { + "internalType": "uint32", + "name": "blockTimestamp", + "type": "uint32" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "address", + "name": "winner", + "type": "address" + }, + { + "internalType": "uint256", + "name": "nounId", + "type": "uint256" + }, + { + "internalType": "uint32", + "name": "clientId", + "type": "uint32" + } + ], + "internalType": "struct INounsAuctionHouseV2.Settlement[]", + "name": "settlements", + "type": "tuple[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "startId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "endId", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "skipEmptyValues", + "type": "bool" + } + ], + "name": "getSettlements", + "outputs": [ + { + "components": [ + { + "internalType": "uint32", + "name": "blockTimestamp", + "type": "uint32" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "address", + "name": "winner", + "type": "address" + }, + { + "internalType": "uint256", + "name": "nounId", + "type": "uint256" + }, + { + "internalType": "uint32", + "name": "clientId", + "type": "uint32" + } + ], + "internalType": "struct INounsAuctionHouseV2.Settlement[]", + "name": "settlements", + "type": "tuple[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "startId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "endTimestamp", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "skipEmptyValues", + "type": "bool" + } + ], + "name": "getSettlementsFromIdtoTimestamp", + "outputs": [ + { + "components": [ + { + "internalType": "uint32", + "name": "blockTimestamp", + "type": "uint32" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "address", + "name": "winner", + "type": "address" + }, + { + "internalType": "uint256", + "name": "nounId", + "type": "uint256" + }, + { + "internalType": "uint32", + "name": "clientId", + "type": "uint32" + } + ], + "internalType": "struct INounsAuctionHouseV2.Settlement[]", + "name": "settlements", + "type": "tuple[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint192", + "name": "_reservePrice", + "type": "uint192" + }, + { + "internalType": "uint56", + "name": "_timeBuffer", + "type": "uint56" + }, + { + "internalType": "uint8", + "name": "_minBidIncrementPercentage", + "type": "uint8" + } + ], + "name": "initialize", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "minBidIncrementPercentage", + "outputs": [ + { + "internalType": "uint8", + "name": "", + "type": "uint8" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "nouns", + "outputs": [ + { + "internalType": "contract INounsToken", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "pause", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "paused", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "renounceOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "reservePrice", + "outputs": [ + { + "internalType": "uint192", + "name": "", + "type": "uint192" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint8", + "name": "_minBidIncrementPercentage", + "type": "uint8" + } + ], + "name": "setMinBidIncrementPercentage", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "uint32", + "name": "blockTimestamp", + "type": "uint32" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "address", + "name": "winner", + "type": "address" + }, + { + "internalType": "uint256", + "name": "nounId", + "type": "uint256" + } + ], + "internalType": "struct INounsAuctionHouseV2.SettlementNoClientId[]", + "name": "settlements", + "type": "tuple[]" + } + ], + "name": "setPrices", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint192", + "name": "_reservePrice", + "type": "uint192" + } + ], + "name": "setReservePrice", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint56", + "name": "_timeBuffer", + "type": "uint56" + } + ], + "name": "setTimeBuffer", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "settleAuction", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "settleCurrentAndCreateNewAuction", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "timeBuffer", + "outputs": [ + { + "internalType": "uint56", + "name": "", + "type": "uint56" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "unpause", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "startId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "endId", + "type": "uint256" + } + ], + "name": "warmUpSettlementState", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "weth", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + } +] diff --git a/packages/nouns-contracts/abi/contracts/governance/NounsDAOLogicV4.json b/packages/nouns-contracts/abi/contracts/governance/NounsDAOLogicV4.json new file mode 100644 index 0000000000..11ac42eabf --- /dev/null +++ b/packages/nouns-contracts/abi/contracts/governance/NounsDAOLogicV4.json @@ -0,0 +1,3122 @@ +[ + { + "inputs": [], + "name": "AdminOnly", + "type": "error" + }, + { + "inputs": [], + "name": "CanOnlyInitializeOnce", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidNounsAddress", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidTimelockAddress", + "type": "error" + }, + { + "inputs": [], + "name": "MustProvideActions", + "type": "error" + }, + { + "inputs": [], + "name": "ProposalInfoArityMismatch", + "type": "error" + }, + { + "inputs": [], + "name": "ProposerAlreadyHasALiveProposal", + "type": "error" + }, + { + "inputs": [], + "name": "TooManyActions", + "type": "error" + }, + { + "inputs": [], + "name": "UnsafeUint16Cast", + "type": "error" + }, + { + "inputs": [], + "name": "VotesBelowProposalThreshold", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "numTokens", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address", + "name": "to", + "type": "address" + } + ], + "name": "DAONounsSupplyIncreasedFromEscrow", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256[]", + "name": "tokenIds", + "type": "uint256[]" + }, + { + "indexed": false, + "internalType": "address", + "name": "to", + "type": "address" + } + ], + "name": "DAOWithdrawNounsFromEscrow", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address[]", + "name": "oldErc20Tokens", + "type": "address[]" + }, + { + "indexed": false, + "internalType": "address[]", + "name": "newErc20tokens", + "type": "address[]" + } + ], + "name": "ERC20TokensToIncludeInForkSet", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint32", + "name": "forkId", + "type": "uint32" + }, + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256[]", + "name": "tokenIds", + "type": "uint256[]" + }, + { + "indexed": false, + "internalType": "uint256[]", + "name": "proposalIds", + "type": "uint256[]" + }, + { + "indexed": false, + "internalType": "string", + "name": "reason", + "type": "string" + } + ], + "name": "EscrowedToFork", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint32", + "name": "forkId", + "type": "uint32" + }, + { + "indexed": false, + "internalType": "address", + "name": "forkTreasury", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "forkToken", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "forkEndTimestamp", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "tokensInEscrow", + "type": "uint256" + } + ], + "name": "ExecuteFork", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "oldForkDAODeployer", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "newForkDAODeployer", + "type": "address" + } + ], + "name": "ForkDAODeployerSet", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "oldForkPeriod", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newForkPeriod", + "type": "uint256" + } + ], + "name": "ForkPeriodSet", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "oldForkThreshold", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newForkThreshold", + "type": "uint256" + } + ], + "name": "ForkThresholdSet", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint32", + "name": "forkId", + "type": "uint32" + }, + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256[]", + "name": "tokenIds", + "type": "uint256[]" + }, + { + "indexed": false, + "internalType": "uint256[]", + "name": "proposalIds", + "type": "uint256[]" + }, + { + "indexed": false, + "internalType": "string", + "name": "reason", + "type": "string" + } + ], + "name": "JoinFork", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint32", + "name": "oldLastMinuteWindowInBlocks", + "type": "uint32" + }, + { + "indexed": false, + "internalType": "uint32", + "name": "newLastMinuteWindowInBlocks", + "type": "uint32" + } + ], + "name": "LastMinuteWindowSet", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint16", + "name": "oldMaxQuorumVotesBPS", + "type": "uint16" + }, + { + "indexed": false, + "internalType": "uint16", + "name": "newMaxQuorumVotesBPS", + "type": "uint16" + } + ], + "name": "MaxQuorumVotesBPSSet", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint16", + "name": "oldMinQuorumVotesBPS", + "type": "uint16" + }, + { + "indexed": false, + "internalType": "uint16", + "name": "newMinQuorumVotesBPS", + "type": "uint16" + } + ], + "name": "MinQuorumVotesBPSSet", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "oldAdmin", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "newAdmin", + "type": "address" + } + ], + "name": "NewAdmin", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "oldImplementation", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "newImplementation", + "type": "address" + } + ], + "name": "NewImplementation", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "oldPendingAdmin", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "newPendingAdmin", + "type": "address" + } + ], + "name": "NewPendingAdmin", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "oldPendingVetoer", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "newPendingVetoer", + "type": "address" + } + ], + "name": "NewPendingVetoer", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "oldVetoer", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "newVetoer", + "type": "address" + } + ], + "name": "NewVetoer", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint32", + "name": "oldObjectionPeriodDurationInBlocks", + "type": "uint32" + }, + { + "indexed": false, + "internalType": "uint32", + "name": "newObjectionPeriodDurationInBlocks", + "type": "uint32" + } + ], + "name": "ObjectionPeriodDurationSet", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "id", + "type": "uint256" + } + ], + "name": "ProposalCanceled", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "id", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address", + "name": "proposer", + "type": "address" + }, + { + "indexed": false, + "internalType": "address[]", + "name": "targets", + "type": "address[]" + }, + { + "indexed": false, + "internalType": "uint256[]", + "name": "values", + "type": "uint256[]" + }, + { + "indexed": false, + "internalType": "string[]", + "name": "signatures", + "type": "string[]" + }, + { + "indexed": false, + "internalType": "bytes[]", + "name": "calldatas", + "type": "bytes[]" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "startBlock", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "endBlock", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "string", + "name": "description", + "type": "string" + } + ], + "name": "ProposalCreated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "id", + "type": "uint256" + } + ], + "name": "ProposalCreatedOnTimelockV1", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "id", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address", + "name": "proposer", + "type": "address" + }, + { + "indexed": false, + "internalType": "address[]", + "name": "targets", + "type": "address[]" + }, + { + "indexed": false, + "internalType": "uint256[]", + "name": "values", + "type": "uint256[]" + }, + { + "indexed": false, + "internalType": "string[]", + "name": "signatures", + "type": "string[]" + }, + { + "indexed": false, + "internalType": "bytes[]", + "name": "calldatas", + "type": "bytes[]" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "startBlock", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "endBlock", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "proposalThreshold", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "quorumVotes", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "string", + "name": "description", + "type": "string" + } + ], + "name": "ProposalCreatedWithRequirements", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "id", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address[]", + "name": "signers", + "type": "address[]" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "updatePeriodEndBlock", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "proposalThreshold", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "quorumVotes", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "uint32", + "name": "clientId", + "type": "uint32" + } + ], + "name": "ProposalCreatedWithRequirements", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "id", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "address", + "name": "proposer", + "type": "address" + }, + { + "indexed": false, + "internalType": "string", + "name": "description", + "type": "string" + }, + { + "indexed": false, + "internalType": "string", + "name": "updateMessage", + "type": "string" + } + ], + "name": "ProposalDescriptionUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "id", + "type": "uint256" + } + ], + "name": "ProposalExecuted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "id", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "objectionPeriodEndBlock", + "type": "uint256" + } + ], + "name": "ProposalObjectionPeriodSet", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "id", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "eta", + "type": "uint256" + } + ], + "name": "ProposalQueued", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "oldProposalThresholdBPS", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newProposalThresholdBPS", + "type": "uint256" + } + ], + "name": "ProposalThresholdBPSSet", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "id", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "address", + "name": "proposer", + "type": "address" + }, + { + "indexed": false, + "internalType": "address[]", + "name": "targets", + "type": "address[]" + }, + { + "indexed": false, + "internalType": "uint256[]", + "name": "values", + "type": "uint256[]" + }, + { + "indexed": false, + "internalType": "string[]", + "name": "signatures", + "type": "string[]" + }, + { + "indexed": false, + "internalType": "bytes[]", + "name": "calldatas", + "type": "bytes[]" + }, + { + "indexed": false, + "internalType": "string", + "name": "updateMessage", + "type": "string" + } + ], + "name": "ProposalTransactionsUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint32", + "name": "oldProposalUpdatablePeriodInBlocks", + "type": "uint32" + }, + { + "indexed": false, + "internalType": "uint32", + "name": "newProposalUpdatablePeriodInBlocks", + "type": "uint32" + } + ], + "name": "ProposalUpdatablePeriodSet", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "id", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "address", + "name": "proposer", + "type": "address" + }, + { + "indexed": false, + "internalType": "address[]", + "name": "targets", + "type": "address[]" + }, + { + "indexed": false, + "internalType": "uint256[]", + "name": "values", + "type": "uint256[]" + }, + { + "indexed": false, + "internalType": "string[]", + "name": "signatures", + "type": "string[]" + }, + { + "indexed": false, + "internalType": "bytes[]", + "name": "calldatas", + "type": "bytes[]" + }, + { + "indexed": false, + "internalType": "string", + "name": "description", + "type": "string" + }, + { + "indexed": false, + "internalType": "string", + "name": "updateMessage", + "type": "string" + } + ], + "name": "ProposalUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "id", + "type": "uint256" + } + ], + "name": "ProposalVetoed", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint32", + "name": "oldQuorumCoefficient", + "type": "uint32" + }, + { + "indexed": false, + "internalType": "uint32", + "name": "newQuorumCoefficient", + "type": "uint32" + } + ], + "name": "QuorumCoefficientSet", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "oldQuorumVotesBPS", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newQuorumVotesBPS", + "type": "uint256" + } + ], + "name": "QuorumVotesBPSSet", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "voter", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "refundAmount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "bool", + "name": "refundSent", + "type": "bool" + } + ], + "name": "RefundableVote", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "signer", + "type": "address" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "sig", + "type": "bytes" + } + ], + "name": "SignatureCancelled", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "timelock", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "timelockV1", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "admin", + "type": "address" + } + ], + "name": "TimelocksAndAdminSet", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "voter", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "proposalId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint8", + "name": "support", + "type": "uint8" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "votes", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "string", + "name": "reason", + "type": "string" + } + ], + "name": "VoteCast", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "voter", + "type": "address" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "proposalId", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "uint32", + "name": "clientId", + "type": "uint32" + } + ], + "name": "VoteCastWithClientId", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "oldVoteSnapshotBlockSwitchProposalId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newVoteSnapshotBlockSwitchProposalId", + "type": "uint256" + } + ], + "name": "VoteSnapshotBlockSwitchProposalIdSet", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "oldVotingDelay", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newVotingDelay", + "type": "uint256" + } + ], + "name": "VotingDelaySet", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "oldVotingPeriod", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newVotingPeriod", + "type": "uint256" + } + ], + "name": "VotingPeriodSet", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "bool", + "name": "sent", + "type": "bool" + } + ], + "name": "Withdraw", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint32", + "name": "forkId", + "type": "uint32" + }, + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256[]", + "name": "tokenIds", + "type": "uint256[]" + } + ], + "name": "WithdrawFromForkEscrow", + "type": "event" + }, + { + "stateMutability": "payable", + "type": "fallback" + }, + { + "inputs": [], + "name": "MAX_PROPOSAL_THRESHOLD_BPS", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [], + "name": "MAX_VOTING_DELAY", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [], + "name": "MAX_VOTING_PERIOD", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [], + "name": "MIN_PROPOSAL_THRESHOLD_BPS", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [], + "name": "MIN_VOTING_DELAY", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [], + "name": "MIN_VOTING_PERIOD", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [], + "name": "adjustedTotalSupply", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "proposalId", + "type": "uint256" + } + ], + "name": "cancel", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "sig", + "type": "bytes" + } + ], + "name": "cancelSig", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "proposalId", + "type": "uint256" + }, + { + "internalType": "uint8", + "name": "support", + "type": "uint8" + } + ], + "name": "castRefundableVote", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "proposalId", + "type": "uint256" + }, + { + "internalType": "uint8", + "name": "support", + "type": "uint8" + }, + { + "internalType": "uint32", + "name": "clientId", + "type": "uint32" + } + ], + "name": "castRefundableVote", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "proposalId", + "type": "uint256" + }, + { + "internalType": "uint8", + "name": "support", + "type": "uint8" + }, + { + "internalType": "string", + "name": "reason", + "type": "string" + } + ], + "name": "castRefundableVoteWithReason", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "proposalId", + "type": "uint256" + }, + { + "internalType": "uint8", + "name": "support", + "type": "uint8" + }, + { + "internalType": "string", + "name": "reason", + "type": "string" + }, + { + "internalType": "uint32", + "name": "clientId", + "type": "uint32" + } + ], + "name": "castRefundableVoteWithReason", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "proposalId", + "type": "uint256" + }, + { + "internalType": "uint8", + "name": "support", + "type": "uint8" + } + ], + "name": "castVote", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "proposalId", + "type": "uint256" + }, + { + "internalType": "uint8", + "name": "support", + "type": "uint8" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + } + ], + "name": "castVoteBySig", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "proposalId", + "type": "uint256" + }, + { + "internalType": "uint8", + "name": "support", + "type": "uint8" + }, + { + "internalType": "string", + "name": "reason", + "type": "string" + } + ], + "name": "castVoteWithReason", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "againstVotes", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "adjustedTotalSupply_", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "uint16", + "name": "minQuorumVotesBPS", + "type": "uint16" + }, + { + "internalType": "uint16", + "name": "maxQuorumVotesBPS", + "type": "uint16" + }, + { + "internalType": "uint32", + "name": "quorumCoefficient", + "type": "uint32" + } + ], + "internalType": "struct NounsDAOStorageV3.DynamicQuorumParams", + "name": "params", + "type": "tuple" + } + ], + "name": "dynamicQuorumVotes", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [], + "name": "erc20TokensToIncludeInFork", + "outputs": [ + { + "internalType": "address[]", + "name": "", + "type": "address[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256[]", + "name": "tokenIds", + "type": "uint256[]" + }, + { + "internalType": "uint256[]", + "name": "proposalIds", + "type": "uint256[]" + }, + { + "internalType": "string", + "name": "reason", + "type": "string" + } + ], + "name": "escrowToFork", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "proposalId", + "type": "uint256" + } + ], + "name": "execute", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "executeFork", + "outputs": [ + { + "internalType": "address", + "name": "forkTreasury", + "type": "address" + }, + { + "internalType": "address", + "name": "forkToken", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "forkDAODeployer", + "outputs": [ + { + "internalType": "contract IForkDAODeployer", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "forkEndTimestamp", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "forkEscrow", + "outputs": [ + { + "internalType": "contract INounsDAOForkEscrow", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "forkPeriod", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "forkThreshold", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "forkThresholdBPS", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "proposalId", + "type": "uint256" + } + ], + "name": "getActions", + "outputs": [ + { + "internalType": "address[]", + "name": "targets", + "type": "address[]" + }, + { + "internalType": "uint256[]", + "name": "values", + "type": "uint256[]" + }, + { + "internalType": "string[]", + "name": "signatures", + "type": "string[]" + }, + { + "internalType": "bytes[]", + "name": "calldatas", + "type": "bytes[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "blockNumber_", + "type": "uint256" + } + ], + "name": "getDynamicQuorumParamsAt", + "outputs": [ + { + "components": [ + { + "internalType": "uint16", + "name": "minQuorumVotesBPS", + "type": "uint16" + }, + { + "internalType": "uint16", + "name": "maxQuorumVotesBPS", + "type": "uint16" + }, + { + "internalType": "uint32", + "name": "quorumCoefficient", + "type": "uint32" + } + ], + "internalType": "struct NounsDAOStorageV3.DynamicQuorumParams", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "proposalId", + "type": "uint256" + }, + { + "internalType": "address", + "name": "voter", + "type": "address" + } + ], + "name": "getReceipt", + "outputs": [ + { + "components": [ + { + "internalType": "bool", + "name": "hasVoted", + "type": "bool" + }, + { + "internalType": "uint8", + "name": "support", + "type": "uint8" + }, + { + "internalType": "uint96", + "name": "votes", + "type": "uint96" + } + ], + "internalType": "struct NounsDAOStorageV3.Receipt", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "timelock_", + "type": "address" + }, + { + "internalType": "address", + "name": "nouns_", + "type": "address" + }, + { + "internalType": "address", + "name": "forkEscrow_", + "type": "address" + }, + { + "internalType": "address", + "name": "forkDAODeployer_", + "type": "address" + }, + { + "internalType": "address", + "name": "vetoer_", + "type": "address" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "votingPeriod", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "votingDelay", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "proposalThresholdBPS", + "type": "uint256" + }, + { + "internalType": "uint32", + "name": "lastMinuteWindowInBlocks", + "type": "uint32" + }, + { + "internalType": "uint32", + "name": "objectionPeriodDurationInBlocks", + "type": "uint32" + }, + { + "internalType": "uint32", + "name": "proposalUpdatablePeriodInBlocks", + "type": "uint32" + } + ], + "internalType": "struct NounsDAOStorageV3.NounsDAOParams", + "name": "daoParams_", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "uint16", + "name": "minQuorumVotesBPS", + "type": "uint16" + }, + { + "internalType": "uint16", + "name": "maxQuorumVotesBPS", + "type": "uint16" + }, + { + "internalType": "uint32", + "name": "quorumCoefficient", + "type": "uint32" + } + ], + "internalType": "struct NounsDAOStorageV3.DynamicQuorumParams", + "name": "dynamicQuorumParams_", + "type": "tuple" + } + ], + "name": "initialize", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256[]", + "name": "tokenIds", + "type": "uint256[]" + }, + { + "internalType": "uint256[]", + "name": "proposalIds", + "type": "uint256[]" + }, + { + "internalType": "string", + "name": "reason", + "type": "string" + } + ], + "name": "joinFork", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "lastMinuteWindowInBlocks", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "latestProposalIds", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "maxQuorumVotes", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "minQuorumVotes", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "nouns", + "outputs": [ + { + "internalType": "contract NounsTokenLike", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "numTokensInForkEscrow", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "objectionPeriodDurationInBlocks", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "pendingVetoer", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "proposalId", + "type": "uint256" + } + ], + "name": "proposalClientId", + "outputs": [ + { + "internalType": "uint32", + "name": "", + "type": "uint32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "proposalCount", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "proposalId", + "type": "uint256" + } + ], + "name": "proposalDataForRewards", + "outputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "endBlock", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "objectionPeriodEndBlock", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "forVotes", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "againstVotes", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "abstainVotes", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "totalSupply", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "creationTimestamp", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "numSigners", + "type": "uint256" + }, + { + "internalType": "uint32", + "name": "clientId", + "type": "uint32" + } + ], + "internalType": "struct NounsDAOStorageV3.ProposalForRewards", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "proposalMaxOperations", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "pure", + "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": [], + "name": "proposalUpdatablePeriodInBlocks", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "proposalId", + "type": "uint256" + }, + { + "internalType": "uint32", + "name": "clientId", + "type": "uint32" + } + ], + "name": "proposalVoteClientData", + "outputs": [ + { + "components": [ + { + "internalType": "uint32", + "name": "votes", + "type": "uint32" + }, + { + "internalType": "uint32", + "name": "txs", + "type": "uint32" + } + ], + "internalType": "struct NounsDAOStorageV3.ClientVoteData", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "proposalId", + "type": "uint256" + }, + { + "internalType": "uint32[]", + "name": "clientIds", + "type": "uint32[]" + } + ], + "name": "proposalVoteClientsData", + "outputs": [ + { + "components": [ + { + "internalType": "uint32", + "name": "votes", + "type": "uint32" + }, + { + "internalType": "uint32", + "name": "txs", + "type": "uint32" + } + ], + "internalType": "struct NounsDAOStorageV3.ClientVoteData[]", + "name": "", + "type": "tuple[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "proposalId", + "type": "uint256" + } + ], + "name": "proposals", + "outputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "id", + "type": "uint256" + }, + { + "internalType": "address", + "name": "proposer", + "type": "address" + }, + { + "internalType": "uint256", + "name": "proposalThreshold", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "quorumVotes", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "eta", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "startBlock", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "endBlock", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "forVotes", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "againstVotes", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "abstainVotes", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "canceled", + "type": "bool" + }, + { + "internalType": "bool", + "name": "vetoed", + "type": "bool" + }, + { + "internalType": "bool", + "name": "executed", + "type": "bool" + }, + { + "internalType": "uint256", + "name": "totalSupply", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "creationBlock", + "type": "uint256" + } + ], + "internalType": "struct NounsDAOStorageV2.ProposalCondensed", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "proposalId", + "type": "uint256" + } + ], + "name": "proposalsV3", + "outputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "id", + "type": "uint256" + }, + { + "internalType": "address", + "name": "proposer", + "type": "address" + }, + { + "internalType": "uint256", + "name": "proposalThreshold", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "quorumVotes", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "eta", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "startBlock", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "endBlock", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "forVotes", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "againstVotes", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "abstainVotes", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "canceled", + "type": "bool" + }, + { + "internalType": "bool", + "name": "vetoed", + "type": "bool" + }, + { + "internalType": "bool", + "name": "executed", + "type": "bool" + }, + { + "internalType": "uint256", + "name": "totalSupply", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "creationBlock", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "creationTimestamp", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "signers", + "type": "address[]" + }, + { + "internalType": "uint256", + "name": "updatePeriodEndBlock", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "objectionPeriodEndBlock", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "executeOnTimelockV1", + "type": "bool" + } + ], + "internalType": "struct NounsDAOStorageV3.ProposalCondensed", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address[]", + "name": "targets", + "type": "address[]" + }, + { + "internalType": "uint256[]", + "name": "values", + "type": "uint256[]" + }, + { + "internalType": "string[]", + "name": "signatures", + "type": "string[]" + }, + { + "internalType": "bytes[]", + "name": "calldatas", + "type": "bytes[]" + }, + { + "internalType": "string", + "name": "description", + "type": "string" + }, + { + "internalType": "uint32", + "name": "clientId", + "type": "uint32" + } + ], + "name": "propose", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address[]", + "name": "targets", + "type": "address[]" + }, + { + "internalType": "uint256[]", + "name": "values", + "type": "uint256[]" + }, + { + "internalType": "string[]", + "name": "signatures", + "type": "string[]" + }, + { + "internalType": "bytes[]", + "name": "calldatas", + "type": "bytes[]" + }, + { + "internalType": "string", + "name": "description", + "type": "string" + } + ], + "name": "propose", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "bytes", + "name": "sig", + "type": "bytes" + }, + { + "internalType": "address", + "name": "signer", + "type": "address" + }, + { + "internalType": "uint256", + "name": "expirationTimestamp", + "type": "uint256" + } + ], + "internalType": "struct NounsDAOStorageV3.ProposerSignature[]", + "name": "proposerSignatures", + "type": "tuple[]" + }, + { + "internalType": "address[]", + "name": "targets", + "type": "address[]" + }, + { + "internalType": "uint256[]", + "name": "values", + "type": "uint256[]" + }, + { + "internalType": "string[]", + "name": "signatures", + "type": "string[]" + }, + { + "internalType": "bytes[]", + "name": "calldatas", + "type": "bytes[]" + }, + { + "internalType": "string", + "name": "description", + "type": "string" + } + ], + "name": "proposeBySigs", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "bytes", + "name": "sig", + "type": "bytes" + }, + { + "internalType": "address", + "name": "signer", + "type": "address" + }, + { + "internalType": "uint256", + "name": "expirationTimestamp", + "type": "uint256" + } + ], + "internalType": "struct NounsDAOStorageV3.ProposerSignature[]", + "name": "proposerSignatures", + "type": "tuple[]" + }, + { + "internalType": "address[]", + "name": "targets", + "type": "address[]" + }, + { + "internalType": "uint256[]", + "name": "values", + "type": "uint256[]" + }, + { + "internalType": "string[]", + "name": "signatures", + "type": "string[]" + }, + { + "internalType": "bytes[]", + "name": "calldatas", + "type": "bytes[]" + }, + { + "internalType": "string", + "name": "description", + "type": "string" + }, + { + "internalType": "uint32", + "name": "clientId", + "type": "uint32" + } + ], + "name": "proposeBySigs", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address[]", + "name": "targets", + "type": "address[]" + }, + { + "internalType": "uint256[]", + "name": "values", + "type": "uint256[]" + }, + { + "internalType": "string[]", + "name": "signatures", + "type": "string[]" + }, + { + "internalType": "bytes[]", + "name": "calldatas", + "type": "bytes[]" + }, + { + "internalType": "string", + "name": "description", + "type": "string" + } + ], + "name": "proposeOnTimelockV1", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "proposalId", + "type": "uint256" + } + ], + "name": "queue", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "quorumParamsCheckpoints", + "outputs": [ + { + "components": [ + { + "internalType": "uint32", + "name": "fromBlock", + "type": "uint32" + }, + { + "components": [ + { + "internalType": "uint16", + "name": "minQuorumVotesBPS", + "type": "uint16" + }, + { + "internalType": "uint16", + "name": "maxQuorumVotesBPS", + "type": "uint16" + }, + { + "internalType": "uint32", + "name": "quorumCoefficient", + "type": "uint32" + } + ], + "internalType": "struct NounsDAOStorageV3.DynamicQuorumParams", + "name": "params", + "type": "tuple" + } + ], + "internalType": "struct NounsDAOStorageV3.DynamicQuorumParamsCheckpoint[]", + "name": "", + "type": "tuple[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "index", + "type": "uint256" + } + ], + "name": "quorumParamsCheckpoints", + "outputs": [ + { + "components": [ + { + "internalType": "uint32", + "name": "fromBlock", + "type": "uint32" + }, + { + "components": [ + { + "internalType": "uint16", + "name": "minQuorumVotesBPS", + "type": "uint16" + }, + { + "internalType": "uint16", + "name": "maxQuorumVotesBPS", + "type": "uint16" + }, + { + "internalType": "uint32", + "name": "quorumCoefficient", + "type": "uint32" + } + ], + "internalType": "struct NounsDAOStorageV3.DynamicQuorumParams", + "name": "params", + "type": "tuple" + } + ], + "internalType": "struct NounsDAOStorageV3.DynamicQuorumParamsCheckpoint", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "proposalId", + "type": "uint256" + } + ], + "name": "quorumVotes", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "quorumVotesBPS", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "proposalId", + "type": "uint256" + } + ], + "name": "state", + "outputs": [ + { + "internalType": "enum NounsDAOStorageV3.ProposalState", + "name": "", + "type": "uint8" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "timelock", + "outputs": [ + { + "internalType": "contract INounsDAOExecutor", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "timelockV1", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "proposalId", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "targets", + "type": "address[]" + }, + { + "internalType": "uint256[]", + "name": "values", + "type": "uint256[]" + }, + { + "internalType": "string[]", + "name": "signatures", + "type": "string[]" + }, + { + "internalType": "bytes[]", + "name": "calldatas", + "type": "bytes[]" + }, + { + "internalType": "string", + "name": "description", + "type": "string" + }, + { + "internalType": "string", + "name": "updateMessage", + "type": "string" + } + ], + "name": "updateProposal", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "proposalId", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "bytes", + "name": "sig", + "type": "bytes" + }, + { + "internalType": "address", + "name": "signer", + "type": "address" + }, + { + "internalType": "uint256", + "name": "expirationTimestamp", + "type": "uint256" + } + ], + "internalType": "struct NounsDAOStorageV3.ProposerSignature[]", + "name": "proposerSignatures", + "type": "tuple[]" + }, + { + "internalType": "address[]", + "name": "targets", + "type": "address[]" + }, + { + "internalType": "uint256[]", + "name": "values", + "type": "uint256[]" + }, + { + "internalType": "string[]", + "name": "signatures", + "type": "string[]" + }, + { + "internalType": "bytes[]", + "name": "calldatas", + "type": "bytes[]" + }, + { + "internalType": "string", + "name": "description", + "type": "string" + }, + { + "internalType": "string", + "name": "updateMessage", + "type": "string" + } + ], + "name": "updateProposalBySigs", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "proposalId", + "type": "uint256" + }, + { + "internalType": "string", + "name": "description", + "type": "string" + }, + { + "internalType": "string", + "name": "updateMessage", + "type": "string" + } + ], + "name": "updateProposalDescription", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "proposalId", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "targets", + "type": "address[]" + }, + { + "internalType": "uint256[]", + "name": "values", + "type": "uint256[]" + }, + { + "internalType": "string[]", + "name": "signatures", + "type": "string[]" + }, + { + "internalType": "bytes[]", + "name": "calldatas", + "type": "bytes[]" + }, + { + "internalType": "string", + "name": "updateMessage", + "type": "string" + } + ], + "name": "updateProposalTransactions", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "proposalId", + "type": "uint256" + } + ], + "name": "veto", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "vetoer", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "voteSnapshotBlockSwitchProposalId", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "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" + }, + { + "inputs": [ + { + "internalType": "uint256[]", + "name": "tokenIds", + "type": "uint256[]" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + } + ], + "name": "withdrawDAONounsFromEscrowIncreasingTotalSupply", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256[]", + "name": "tokenIds", + "type": "uint256[]" + } + ], + "name": "withdrawDAONounsFromEscrowToTreasury", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256[]", + "name": "tokenIds", + "type": "uint256[]" + } + ], + "name": "withdrawFromForkEscrow", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "stateMutability": "payable", + "type": "receive" + } +] diff --git a/packages/nouns-contracts/audits/2024-04-23_client_incentives_sherlock_audit_report.pdf b/packages/nouns-contracts/audits/2024-04-23_client_incentives_sherlock_audit_report.pdf new file mode 100644 index 0000000000..0876fa8973 Binary files /dev/null and b/packages/nouns-contracts/audits/2024-04-23_client_incentives_sherlock_audit_report.pdf differ diff --git a/packages/nouns-contracts/broadcast/DeployAuctionHouseV2Mainnet.s.sol/1/run-1713864636.json b/packages/nouns-contracts/broadcast/DeployAuctionHouseV2Mainnet.s.sol/1/run-1713864636.json new file mode 100644 index 0000000000..2b91d49aa1 --- /dev/null +++ b/packages/nouns-contracts/broadcast/DeployAuctionHouseV2Mainnet.s.sol/1/run-1713864636.json @@ -0,0 +1,99 @@ +{ + "transactions": [ + { + "hash": "0xc5e5b47fd700d2a4471389f4c1ee759c9a82d77eefdbb683283a4d91c59f1fa6", + "transactionType": "CREATE", + "contractName": "NounsAuctionHouseV2", + "contractAddress": "0x2fdadd994b1edefd19744f00d1afe85045a31561", + "function": null, + "arguments": [ + "0x9C8fF314C9Bc7F6e59A9d9225Fb22946427eDC03", + "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", + "86400" + ], + "transaction": { + "from": "0x918895f466eb3cd5fb181626f8e1b2fd8a9d5192", + "to": null, + "gas": "0x346bd6", + "value": "0x0", + "input": "0x60e06040523480156200001157600080fd5b506040516200302438038062003024833981016040819052620000349162000127565b600054610100900460ff16806200004e575060005460ff16155b620000b65760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b606482015260840160405180910390fd5b600054610100900460ff16158015620000d9576000805461ffff19166101011790555b6001600160a01b03808516608052831660a05260c0829052801562000104576000805461ff00191690555b505050506200016f565b6001600160a01b03811681146200012457600080fd5b50565b6000806000606084860312156200013d57600080fd5b83516200014a816200010e565b60208501519093506200015d816200010e565b80925050604084015190509250925092565b60805160a05160c051612e5b620001c96000396000818161023c0152611ca40152600081816102ff0152818161243e01526124d301526000818161027e01528181611be30152818161217201526122170152612e5b6000f3fe6080604052600436106101cd5760003560e01c80638da5cb5b116100f7578063af64dd3011610095578063db2e1eed11610064578063db2e1eed14610768578063ec91f2a4146107a0578063f25efffc146107c7578063f2fde38b146107dc57600080fd5b8063af64dd30146106d5578063b1296a94146106f5578063b296024d14610715578063c0555d981461074857600080fd5b80639903cce6116100d15780639903cce61461066d578063a4d0a17e1461068d578063a94dd8a0146106a2578063abbfb786146106c257600080fd5b80638da5cb5b1461054b5780639149295614610569578063945c37cb1461059657600080fd5b80635112fabf1161016f578063715018a61161013e578063715018a6146103c25780637d9f6db5146103d75780638456cb591461050757806385317a291461051c57600080fd5b80635112fabf146103215780635c975abb14610341578063659dd2b4146103645780636dd83b5d1461037757600080fd5b80632de45f18116101ab5780632de45f181461026c57806336ebdb38146102b85780633f4ba83a146102d85780633fc8cef3146102ed57600080fd5b806309b85709146101d25780630ba4e9ea146102085780630fb5a6b41461022a575b600080fd5b3480156101de57600080fd5b506101f26101ed366004612746565b6107fc565b6040516101ff919061277f565b60405180910390f35b34801561021457600080fd5b5061022861022336600461281b565b610a4f565b005b34801561023657600080fd5b5061025e7f000000000000000000000000000000000000000000000000000000000000000081565b6040519081526020016101ff565b34801561027857600080fd5b506102a07f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020016101ff565b3480156102c457600080fd5b506102286102d336600461284e565b610b2d565b3480156102e457600080fd5b50610228610bfa565b3480156102f957600080fd5b506102a07f000000000000000000000000000000000000000000000000000000000000000081565b34801561032d57600080fd5b5061022861033c366004612869565b610c5a565b34801561034d57600080fd5b5060335460ff1660405190151581526020016101ff565b61022861037236600461288b565b610cd6565b34801561038357600080fd5b506103ad61039236600461288b565b600090815260cc602052604090206001015463ffffffff1690565b60405163ffffffff90911681526020016101ff565b3480156103ce57600080fd5b50610228610ce4565b3480156103e357600080fd5b506104946040805160c081018252600080825260208201819052918101829052606081018290526080810182905260a0810191909152506040805160c08101825260ca546001600160601b0381168252600160801b90046001600160801b0316602082015260cb5464ffffffffff80821693830193909352600160281b81049092166060820152600160501b82046001600160a01b03166080820152600160f01b90910460ff16151560a082015290565b6040516101ff919081516001600160601b031681526020808301516001600160801b03169082015260408083015164ffffffffff90811691830191909152606080840151909116908201526080808301516001600160a01b03169082015260a09182015115159181019190915260c00190565b34801561051357600080fd5b50610228610d18565b34801561052857600080fd5b506105336201518081565b60405166ffffffffffffff90911681526020016101ff565b34801561055757600080fd5b506097546001600160a01b03166102a0565b34801561057557600080fd5b5061058961058436600461288b565b610d4a565b6040516101ff91906128a4565b3480156105a257600080fd5b5060ca5460cb5461060a916001600160601b03811691600160601b820463ffffffff1691600160801b90046001600160801b03169064ffffffffff80821691600160281b810490911690600160501b81046001600160a01b031690600160f01b900460ff1687565b604080516001600160601b03909816885263ffffffff90961660208801526001600160801b039094169486019490945264ffffffffff91821660608601521660808401526001600160a01b0390911660a0830152151560c082015260e0016101ff565b34801561067957600080fd5b506102286106883660046128ff565b610f61565b34801561069957600080fd5b50610228611032565b3480156106ae57600080fd5b506102286106bd3660046129d4565b611083565b6102286106d0366004612ac8565b6111c0565b3480156106e157600080fd5b506101f26106f0366004612af4565b611602565b34801561070157600080fd5b506101f2610710366004612746565b61180b565b34801561072157600080fd5b5060c95461073690600160f81b900460ff1681565b60405160ff90911681526020016101ff565b34801561075457600080fd5b50610228610763366004612b24565b6119c9565b34801561077457600080fd5b5060c954610788906001600160c01b031681565b6040516001600160c01b0390911681526020016101ff565b3480156107ac57600080fd5b5060c95461053390600160c01b900466ffffffffffffff1681565b3480156107d357600080fd5b50610228611a41565b3480156107e857600080fd5b506102286107f7366004612b3f565b611a97565b60ca546060906001600160601b0316808511156108545760405162461bcd60e51b81526020600482015260116024820152707374617274496420746f6f206c6172676560781b60448201526064015b60405180910390fd5b61085e8582612b70565b610869906001612b83565b6001600160401b0381111561088057610880612942565b6040519080825280602002602001820160405280156108d957816020015b6040805160a08101825260008082526020808301829052928201819052606082018190526080820152825260001990920191018161089e5790505b50915060006108e661270a565b865b838111610a3757600081815260cc6020908152604091829020825160a081018452815463ffffffff8082168352600160201b8083046001600160401b031695840195909552600160601b9091046001600160a01b0316948201949094526001909101549283166060820152910460ff1615156080820152915085801561097957506001826000015163ffffffff1611155b610a2757838114801561099757506001826000015163ffffffff1611155b610a2757815163ffffffff168710610a37576040518060a00160405280836000015163ffffffff1681526020016109d18460200151611b2f565b815260200183604001516001600160a01b03168152602001828152602001836060015163ffffffff16815250858481518110610a0f57610a0f612b96565b602002602001018190525082610a2490612bac565b92505b610a3081612bac565b90506108e8565b508184511115610a45578184525b5050509392505050565b6097546001600160a01b03163314610a795760405162461bcd60e51b815260040161084b90612bc5565b6201518066ffffffffffffff82161115610acc5760405162461bcd60e51b815260206004820152601460248201527374696d6542756666657220746f6f206c6172676560601b604482015260640161084b565b60c9805466ffffffffffffff60c01b1916600160c01b66ffffffffffffff8416908102919091179091556040519081527f1b55d9f7002bda4490f467e326f22a4a847629c0f2d1ed421607d318d25b410d906020015b60405180910390a150565b6097546001600160a01b03163314610b575760405162461bcd60e51b815260040161084b90612bc5565b60008160ff1611610baa5760405162461bcd60e51b815260206004820152601960248201527f6d7573742062652067726561746572207468616e207a65726f00000000000000604482015260640161084b565b60c980546001600160f81b0316600160f81b60ff8416908102919091179091556040519081527fec5ccd96cc77b6219e9d44143df916af68fc169339ea7de5008ff15eae13450d90602001610b22565b6097546001600160a01b03163314610c245760405162461bcd60e51b815260040161084b90612bc5565b610c2c611b4e565b60cb5464ffffffffff161580610c4b575060cb54600160f01b900460ff165b15610c5857610c58611be1565b565b815b81811015610cd15761071c8111158015610c7e5750610c7c600a82612c10565b155b610cc957600081815260cc602052604081208054909163ffffffff9091169003610cc757805463ffffffff1916600190811782558101805464ff000000001916600160201b1790555b505b600101610c5c565b505050565b610ce18160006111c0565b50565b6097546001600160a01b03163314610d0e5760405162461bcd60e51b815260040161084b90612bc5565b610c586000611da0565b6097546001600160a01b03163314610d425760405162461bcd60e51b815260040161084b90612bc5565b610c58611df2565b60ca5460cb546060916001600160601b031690600160f01b900460ff16158015610d745750600081115b15610d8757610d84600182612b70565b90505b826001600160401b03811115610d9f57610d9f612942565b604051908082528060200260200182016040528015610dc8578160200160208202803683370190505b5091506000610dd561270a565b825b600081118015610de657508583105b15610f145761071c8111158015610e055750610e03600a82612c10565b155b610f0457600081815260cc6020908152604091829020825160a081018452815463ffffffff808216808452600160201b8084046001600160401b031696850196909652600160601b9092046001600160a01b03169583019590955260019283015494851660608301529290930460ff161515608084015291935011610ebb5760405162461bcd60e51b815260206004820152600c60248201526b4d697373696e67206461746160a01b604482015260640161084b565b60408201516001600160a01b031615610f0457610edb8260200151611b2f565b858481518110610eed57610eed612b96565b6020908102919091010152610f0183612bac565b92505b610f0d81612c24565b9050610dd7565b50818514610f595760405162461bcd60e51b81526020600482015260126024820152714e6f7420656e6f75676820686973746f727960701b604482015260640161084b565b505050919050565b600054610100900460ff1680610f7a575060005460ff16155b610f965760405162461bcd60e51b815260040161084b90612c3b565b600054610100900460ff16158015610fb8576000805461ffff19166101011790555b610fc0611e6d565b610fc8611ee8565b610fd0611f47565b610fd8611df2565b60c980546001600160c01b0386166001600160f81b031990911617600160c01b66ffffffffffffff861602176001600160f81b0316600160f81b60ff851602179055801561102c576000805461ff00191690555b50505050565b60335460ff1661107b5760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b604482015260640161084b565b610c58611fae565b6097546001600160a01b031633146110ad5760405162461bcd60e51b815260040161084b90612bc5565b60005b81518110156111bc57600060cc60008484815181106110d1576110d1612b96565b602002602001015160600151815260200190815260200160002090508282815181106110ff576110ff612b96565b602090810291909101015151815463ffffffff191663ffffffff90911617815582516111489084908490811061113757611137612b96565b60200260200101516020015161241e565b81546001600160401b0391909116600160201b026bffffffffffffffff0000000019909116178155825183908390811061118457611184612b96565b60209081029190910101516040015181546001600160a01b03909116600160601b026001600160601b039091161790556001016110b0565b5050565b6040805160e08101825260ca546001600160601b038116808352600160601b820463ffffffff166020840152600160801b9091046001600160801b03169282019290925260cb5464ffffffffff8082166060840152600160281b8204166080830152600160501b81046001600160a01b031660a0830152600160f01b900460ff908116151560c083015260c95491926001600160c01b03831692600160c01b810466ffffffffffffff1692600160f81b909104169086146112c35760405162461bcd60e51b815260206004820152601760248201527f4e6f756e206e6f7420757020666f722061756374696f6e000000000000000000604482015260640161084b565b836080015164ffffffffff16421061130f5760405162461bcd60e51b815260206004820152600f60248201526e105d58dd1a5bdb88195e1c1a5c9959608a1b604482015260640161084b565b826001600160c01b03163410156113685760405162461bcd60e51b815260206004820152601f60248201527f4d7573742073656e64206174206c656173742072657365727665507269636500604482015260640161084b565b60648160ff16856040015161137d9190612c89565b6113879190612cb4565b84604001516113969190612cda565b6001600160801b0316341015611416576040805162461bcd60e51b81526020600482015260248101919091527f4d7573742073656e64206d6f7265207468616e206c617374206269642062792060448201527f6d696e426964496e6372656d656e7450657263656e7461676520616d6f756e74606482015260840161084b565b60ca80546001600160601b0316600160601b63ffffffff8816026001600160801b0390811691909117600160801b349092169190910217905560cb80547fffff0000000000000000000000000000000000000000ffffffffffffffffffff1633600160501b02179055608084015160009066ffffffffffffff8416906114a490429064ffffffffff16612b70565b865160408051338152346020820152939092109183018290529092506001600160601b0316907f1159164c56f277e6fc99c11731bd380e0347deb969b75523398734c252706ea39060600160405180910390a263ffffffff86161561154b57845160405134815263ffffffff8816916001600160601b0316907f38e150a71033b4c9a3eeb9ebe568476f075a558e47171f3b5d715aa0cf6cd1b59060200160405180910390a35b80156115cd5761156466ffffffffffffff841642612b83565b64ffffffffff166080860181905260cb805469ffffffffff00000000001916600160281b830217905585516040519182526001600160601b0316907f6e912a3a9105bdd2af817ba5adc14e6c127c1035b5b648faa29ca0d58ab8ff4e9060200160405180910390a25b60a08501516001600160a01b038116156115f8576115f88187604001516001600160801b031661242e565b5050505050505050565b60ca5460cb546060916001600160601b031690600160f01b900460ff1615801561162c5750600081115b1561163f5761163c600182612b70565b90505b836001600160401b0381111561165757611657612942565b6040519080825280602002602001820160405280156116b057816020015b6040805160a0810182526000808252602080830182905292820181905260608201819052608082015282526000199092019101816116755790505b50915060006116bd61270a565b825b868310156117f557600081815260cc6020908152604091829020825160a081018452815463ffffffff8082168352600160201b8083046001600160401b031695840195909552600160601b9091046001600160a01b0316948201949094526001909101549283166060820152910460ff1615156080820152915085801561175157506001826000015163ffffffff1611155b156117615780156117f5576117e5565b6040518060a00160405280836000015163ffffffff1681526020016117898460200151611b2f565b815260200183604001516001600160a01b03168152602001828152602001836060015163ffffffff168152508584815181106117c7576117c7612b96565b6020026020010181905250826117dc90612bac565b925080156117f5575b6117ee81612c24565b90506116bf565b5081861115611802578184525b50505092915050565b60606118178484612b70565b6001600160401b0381111561182e5761182e612942565b60405190808252806020026020018201604052801561188757816020015b6040805160a08101825260008082526020808301829052928201819052606082018190526080820152825260001990920191018161184c5790505b509050600061189461270a565b855b858110156119b257600081815260cc6020908152604091829020825160a081018452815463ffffffff8082168352600160201b8083046001600160401b031695840195909552600160601b9091046001600160a01b0316948201949094526001909101549283166060820152910460ff1615156080820152915084801561192857506001826000015163ffffffff1611155b6119aa576040518060a00160405280836000015163ffffffff1681526020016119548460200151611b2f565b815260200183604001516001600160a01b03168152602001828152602001836060015163ffffffff1681525084848151811061199257611992612b96565b6020026020010181905250826119a790612bac565b92505b600101611896565b5081835111156119c0578183525b50509392505050565b6097546001600160a01b031633146119f35760405162461bcd60e51b815260040161084b90612bc5565b60c980546001600160c01b0319166001600160c01b0383169081179091556040519081527f6ab2e127d7fdf53b8f304e59d3aab5bfe97979f52a85479691a6fab27a28a6b290602001610b22565b60335460ff1615611a875760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b604482015260640161084b565b611a8f611fae565b610c58611be1565b6097546001600160a01b03163314611ac15760405162461bcd60e51b815260040161084b90612bc5565b6001600160a01b038116611b265760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b606482015260840161084b565b610ce181611da0565b6000611b486001600160401b0383166305f5e100612d01565b92915050565b60335460ff16611b975760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b604482015260640161084b565b6033805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316631249c58b6040518163ffffffff1660e01b81526004016020604051808303816000875af1925050508015611c5d575060408051601f3d908101601f19168201909252611c5a91810190612d18565b60015b611c9c57611c69612d31565b806308c379a003611c905750611c7d612d4d565b80611c885750611c92565b610ce1611df2565b505b3d6000803e3d6000fd5b426000611cc97f000000000000000000000000000000000000000000000000000000000000000083612dd6565b6040805160e0810182526001600160601b0386168082526000602080840182905283850182905264ffffffffff888116606086018190529087166080860181905260a0860184905260c09095019290925260ca9290925560cb805469ffffffffffffffffffff19168217600160281b8502177fff000000000000000000000000000000000000000000ffffffffffffffffffff16905583519081529081019190915291925084917fd6eddd1118d71820909c1197aa966dbc15ed6f508554252169cc3d5ccac756ca910160405180910390a2505050565b609780546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b60335460ff1615611e385760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b604482015260640161084b565b6033805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258611bc43390565b600054610100900460ff1680611e86575060005460ff16155b611ea25760405162461bcd60e51b815260040161084b90612c3b565b600054610100900460ff16158015611ec4576000805461ffff19166101011790555b611ecc612544565b611ed46125ae565b8015610ce1576000805461ff001916905550565b600054610100900460ff1680611f01575060005460ff16155b611f1d5760405162461bcd60e51b815260040161084b90612c3b565b600054610100900460ff16158015611f3f576000805461ffff19166101011790555b611ed4612623565b600054610100900460ff1680611f60575060005460ff16155b611f7c5760405162461bcd60e51b815260040161084b90612c3b565b600054610100900460ff16158015611f9e576000805461ffff19166101011790555b611fa6612544565b611ed4612693565b6040805160e08101825260ca546001600160601b0381168252600160601b810463ffffffff166020830152600160801b90046001600160801b03169181019190915260cb5464ffffffffff80821660608401819052600160281b83049091166080840152600160501b82046001600160a01b031660a0840152600160f01b90910460ff16151560c083015260000361207f5760405162461bcd60e51b815260206004820152601460248201527320bab1ba34b7b7103430b9b713ba103132b3bab760611b604482015260640161084b565b8060c00151156120d15760405162461bcd60e51b815260206004820181905260248201527f41756374696f6e2068617320616c7265616479206265656e20736574746c6564604482015260640161084b565b806080015164ffffffffff1642101561212c5760405162461bcd60e51b815260206004820152601860248201527f41756374696f6e206861736e277420636f6d706c657465640000000000000000604482015260640161084b565b60cb805460ff60f01b1916600160f01b17905560a08101516001600160a01b03166121db578051604051630852cd8d60e31b81526001600160601b0390911660048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906342966c6890602401600060405180830381600087803b1580156121be57600080fd5b505af11580156121d2573d6000803e3d6000fd5b50505050612276565b60a081015181516040516323b872dd60e01b81523060048201526001600160a01b0392831660248201526001600160601b0390911660448201527f0000000000000000000000000000000000000000000000000000000000000000909116906323b872dd90606401600060405180830381600087803b15801561225d57600080fd5b505af1158015612271573d6000803e3d6000fd5b505050505b60408101516001600160801b0316156122b1576122b161229e6097546001600160a01b031690565b82604001516001600160801b031661242e565b80516001600160601b0316600090815260cc602052604090819020805463ffffffff19164263ffffffff16178155908201516122f5906001600160801b031661241e565b815460a08401516001600160a01b0316600160601b026001600160601b036001600160401b0393909316600160201b029290921663ffffffff918216179190911782556020830151161561236457602082015160018201805463ffffffff191663ffffffff9092169190911790555b815160a083015160408085015181516001600160a01b0390931683526001600160801b031660208301526001600160601b03909216917fc9f72b276a388619c6d185d146697036241880c36654b1a3ffdad07c24038d99910160405180910390a2602082015163ffffffff16156111bc57816020015163ffffffff1682600001516001600160601b03167ff445afb110f5e782fc78bf23e7066d3c5a95f7b57bd25fb718a29ad0287db2b960405160405180910390a35050565b6000611b486305f5e10083612df4565b61243882826126f3565b6111bc577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b15801561249757600080fd5b505af11580156124ab573d6000803e3d6000fd5b505060405163a9059cbb60e01b81526001600160a01b038681166004830152602482018690527f000000000000000000000000000000000000000000000000000000000000000016935063a9059cbb925060440190506020604051808303816000875af1158015612520573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cd19190612e08565b600054610100900460ff168061255d575060005460ff16155b6125795760405162461bcd60e51b815260040161084b90612c3b565b600054610100900460ff16158015611ed4576000805461ffff19166101011790558015610ce1576000805461ff001916905550565b600054610100900460ff16806125c7575060005460ff16155b6125e35760405162461bcd60e51b815260040161084b90612c3b565b600054610100900460ff16158015612605576000805461ffff19166101011790555b6033805460ff191690558015610ce1576000805461ff001916905550565b600054610100900460ff168061263c575060005460ff16155b6126585760405162461bcd60e51b815260040161084b90612c3b565b600054610100900460ff1615801561267a576000805461ffff19166101011790555b60016065558015610ce1576000805461ff001916905550565b600054610100900460ff16806126ac575060005460ff16155b6126c85760405162461bcd60e51b815260040161084b90612c3b565b600054610100900460ff161580156126ea576000805461ffff19166101011790555b611ed433611da0565b6000806000806000808688617530f1949350505050565b6040805160a08101825260008082526020820181905291810182905260608101829052608081019190915290565b8015158114610ce157600080fd5b60008060006060848603121561275b57600080fd5b8335925060208401359150604084013561277481612738565b809150509250925092565b602080825282518282018190526000919060409081850190868401855b828110156127f2578151805163ffffffff90811686528782015188870152868201516001600160a01b03168787015260608083015190870152608091820151169085015260a0909301929085019060010161279c565b5091979650505050505050565b803566ffffffffffffff8116811461281657600080fd5b919050565b60006020828403121561282d57600080fd5b612836826127ff565b9392505050565b803560ff8116811461281657600080fd5b60006020828403121561286057600080fd5b6128368261283d565b6000806040838503121561287c57600080fd5b50508035926020909101359150565b60006020828403121561289d57600080fd5b5035919050565b6020808252825182820181905260009190848201906040850190845b818110156128dc578351835292840192918401916001016128c0565b50909695505050505050565b80356001600160c01b038116811461281657600080fd5b60008060006060848603121561291457600080fd5b61291d846128e8565b925061292b602085016127ff565b91506129396040850161283d565b90509250925092565b634e487b7160e01b600052604160045260246000fd5b608081018181106001600160401b038211171561297757612977612942565b60405250565b601f8201601f191681016001600160401b03811182821017156129a2576129a2612942565b6040525050565b803563ffffffff8116811461281657600080fd5b80356001600160a01b038116811461281657600080fd5b600060208083850312156129e757600080fd5b82356001600160401b03808211156129fe57600080fd5b818501915085601f830112612a1257600080fd5b813581811115612a2457612a24612942565b60409150604051612a3a858360051b018261297d565b81815260079190911b830184019084810188831115612a5857600080fd5b938501935b82851015612abc576080858a031215612a765760008081fd5b8351612a8181612958565b612a8a866129a9565b81528686013587820152612a9f8587016129bd565b818601526060868101359082015281526080909401938501612a5d565b50979650505050505050565b60008060408385031215612adb57600080fd5b82359150612aeb602084016129a9565b90509250929050565b60008060408385031215612b0757600080fd5b823591506020830135612b1981612738565b809150509250929050565b600060208284031215612b3657600080fd5b612836826128e8565b600060208284031215612b5157600080fd5b612836826129bd565b634e487b7160e01b600052601160045260246000fd5b81810381811115611b4857611b48612b5a565b80820180821115611b4857611b48612b5a565b634e487b7160e01b600052603260045260246000fd5b600060018201612bbe57612bbe612b5a565b5060010190565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b634e487b7160e01b600052601260045260246000fd5b600082612c1f57612c1f612bfa565b500690565b600081612c3357612c33612b5a565b506000190190565b6020808252602e908201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160408201526d191e481a5b9a5d1a585b1a5e995960921b606082015260800190565b6001600160801b03818116838216028082169190828114612cac57612cac612b5a565b505092915050565b60006001600160801b0380841680612cce57612cce612bfa565b92169190910492915050565b6001600160801b03818116838216019080821115612cfa57612cfa612b5a565b5092915050565b8082028115828204841417611b4857611b48612b5a565b600060208284031215612d2a57600080fd5b5051919050565b600060033d1115612d4a5760046000803e5060005160e01c5b90565b600060443d1015612d5b5790565b6040516003193d81016004833e81513d6001600160401b038160248401118184111715612d8a57505050505090565b8285019150815181811115612da25750505050505090565b843d8701016020828501011115612dbc5750505050505090565b612dcb6020828601018761297d565b509095945050505050565b64ffffffffff818116838216019080821115612cfa57612cfa612b5a565b600082612e0357612e03612bfa565b500490565b600060208284031215612e1a57600080fd5b81516128368161273856fea26469706673582212204eed286559142f12f42055a0eba0e732348e19053404b823817c2b809c389e7864736f6c634300081700330000000000000000000000009c8ff314c9bc7f6e59a9d9225fb22946427edc03000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000000000000015180", + "nonce": "0x1", + "chainId": "0x1", + "accessList": null, + "type": null + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x56b39dd0269cbf457ee0d585c90d4c2c9281493834e88993fb94d3dc6ddc6fa0", + "transactionType": "CREATE", + "contractName": "NounsAuctionHousePreV2Migration", + "contractAddress": "0x714f5039c2ca1641b8823469a852513bf6018fa4", + "function": null, + "arguments": null, + "transaction": { + "from": "0x918895f466eb3cd5fb181626f8e1b2fd8a9d5192", + "to": null, + "gas": "0x92cc9", + "value": "0x0", + "input": "0x608060405234801561001057600080fd5b50610769806100206000396000f3fe608060405234801561001057600080fd5b50600436106100575760003560e01c80635c975abb1461005c578063715018a6146100775780638da5cb5b146100815780638fd3ab801461009c578063f2fde38b146100a4575b600080fd5b60335460ff1660405190151581526020015b60405180910390f35b61007f6100b7565b005b6097546040516001600160a01b03909116815260200161006e565b61007f6100f6565b61007f6100b23660046106ce565b6105e1565b6097546001600160a01b031633146100ea5760405162461bcd60e51b81526004016100e1906106fe565b60405180910390fd5b6100f4600061067c565b565b6097546001600160a01b031633146101205760405162461bcd60e51b81526004016100e1906106fe565b600060c99050600060c990506000826040518060e00160405290816000820160009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b031681526020016001820160009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b0316815260200160028201548152602001600382015481526020016004820160009054906101000a900460ff1660ff1660ff16815260200160058201548152602001600682016040518060c0016040529081600082015481526020016001820154815260200160028201548152602001600382015481526020016004820160009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b031681526020016004820160149054906101000a900460ff16151515158152505081525050905060008360000160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060008360010160006101000a8154816001600160a01b0302191690836001600160a01b03160217905550600083600201819055506000836003018190555060008360040160006101000a81548160ff021916908360ff160217905550600083600501819055506040518060c001604052806000815260200160008152602001600081526020016000815260200160006001600160a01b0316815260200160001515815250836006016000820151816000015560208201518160010155604082015181600201556060820151816003015560808201518160040160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060a08201518160040160146101000a81548160ff02191690831515021790555090505080606001518260000160006101000a8154816001600160c01b0302191690836001600160c01b0316021790555080604001518260000160186101000a81548166ffffffffffffff021916908366ffffffffffffff160217905550806080015182600001601f6101000a81548160ff021916908360ff1602179055506040518060e001604052808260c00151600001516001600160601b03168152602001600063ffffffff1681526020018260c00151602001516001600160801b031681526020018260c001516040015164ffffffffff1681526020018260c001516060015164ffffffffff1681526020018260c00151608001516001600160a01b031681526020018260c0015160a0015115158152508260010160008201518160000160006101000a8154816001600160601b0302191690836001600160601b03160217905550602082015181600001600c6101000a81548163ffffffff021916908363ffffffff16021790555060408201518160000160106101000a8154816001600160801b0302191690836001600160801b0316021790555060608201518160010160006101000a81548164ffffffffff021916908364ffffffffff16021790555060808201518160010160056101000a81548164ffffffffff021916908364ffffffffff16021790555060a082015181600101600a6101000a8154816001600160a01b0302191690836001600160a01b0316021790555060c082015181600101601e6101000a81548160ff021916908315150217905550905050505050565b6097546001600160a01b0316331461060b5760405162461bcd60e51b81526004016100e1906106fe565b6001600160a01b0381166106705760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084016100e1565b6106798161067c565b50565b609780546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6000602082840312156106e057600080fd5b81356001600160a01b03811681146106f757600080fd5b9392505050565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260408201526060019056fea2646970667358221220eccf365de37364bac882a745bfa92868d893629bdbb6d40821d4aa7ab61698bd64736f6c63430008170033", + "nonce": "0x2", + "chainId": "0x1", + "accessList": null, + "type": null + }, + "additionalContracts": [], + "isFixedGasLimit": false + } + ], + "receipts": [ + { + "status": "0x1", + "cumulativeGasUsed": "0x939d0e", + "logs": [], + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "type": "0x2", + "transactionHash": "0xc5e5b47fd700d2a4471389f4c1ee759c9a82d77eefdbb683283a4d91c59f1fa6", + "transactionIndex": "0x5a", + "blockHash": "0xcdb00fa8a29f83a5f094d01715eef5298daaa9ee2d22b20799860312087b9f8c", + "blockNumber": "0x12cdc58", + "gasUsed": "0x2855fe", + "effectiveGasPrice": "0x1e176696d", + "from": "0x918895f466eb3cd5fb181626f8e1b2fd8a9d5192", + "to": null, + "contractAddress": "0x2fdadd994b1edefd19744f00d1afe85045a31561" + }, + { + "status": "0x1", + "cumulativeGasUsed": "0x9aac4a", + "logs": [], + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "type": "0x2", + "transactionHash": "0x56b39dd0269cbf457ee0d585c90d4c2c9281493834e88993fb94d3dc6ddc6fa0", + "transactionIndex": "0x5b", + "blockHash": "0xcdb00fa8a29f83a5f094d01715eef5298daaa9ee2d22b20799860312087b9f8c", + "blockNumber": "0x12cdc58", + "gasUsed": "0x70f3c", + "effectiveGasPrice": "0x1e176696d", + "from": "0x918895f466eb3cd5fb181626f8e1b2fd8a9d5192", + "to": null, + "contractAddress": "0x714f5039c2ca1641b8823469a852513bf6018fa4" + } + ], + "libraries": [], + "pending": [], + "returns": { + "newLogic": { + "internal_type": "contract NounsAuctionHouseV2", + "value": "0x2FDAdd994b1eDEfD19744F00d1Afe85045A31561" + }, + "migratorLogic": { + "internal_type": "contract NounsAuctionHousePreV2Migration", + "value": "0x714f5039C2cA1641b8823469a852513bF6018fa4" + } + }, + "timestamp": 1713864636, + "chain": 1, + "commit": "82b8d911" +} \ No newline at end of file diff --git a/packages/nouns-contracts/broadcast/DeployAuctionHouseV2Mainnet.s.sol/1/run-latest.json b/packages/nouns-contracts/broadcast/DeployAuctionHouseV2Mainnet.s.sol/1/run-latest.json new file mode 100644 index 0000000000..2b91d49aa1 --- /dev/null +++ b/packages/nouns-contracts/broadcast/DeployAuctionHouseV2Mainnet.s.sol/1/run-latest.json @@ -0,0 +1,99 @@ +{ + "transactions": [ + { + "hash": "0xc5e5b47fd700d2a4471389f4c1ee759c9a82d77eefdbb683283a4d91c59f1fa6", + "transactionType": "CREATE", + "contractName": "NounsAuctionHouseV2", + "contractAddress": "0x2fdadd994b1edefd19744f00d1afe85045a31561", + "function": null, + "arguments": [ + "0x9C8fF314C9Bc7F6e59A9d9225Fb22946427eDC03", + "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", + "86400" + ], + "transaction": { + "from": "0x918895f466eb3cd5fb181626f8e1b2fd8a9d5192", + "to": null, + "gas": "0x346bd6", + "value": "0x0", + "input": "0x60e06040523480156200001157600080fd5b506040516200302438038062003024833981016040819052620000349162000127565b600054610100900460ff16806200004e575060005460ff16155b620000b65760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b606482015260840160405180910390fd5b600054610100900460ff16158015620000d9576000805461ffff19166101011790555b6001600160a01b03808516608052831660a05260c0829052801562000104576000805461ff00191690555b505050506200016f565b6001600160a01b03811681146200012457600080fd5b50565b6000806000606084860312156200013d57600080fd5b83516200014a816200010e565b60208501519093506200015d816200010e565b80925050604084015190509250925092565b60805160a05160c051612e5b620001c96000396000818161023c0152611ca40152600081816102ff0152818161243e01526124d301526000818161027e01528181611be30152818161217201526122170152612e5b6000f3fe6080604052600436106101cd5760003560e01c80638da5cb5b116100f7578063af64dd3011610095578063db2e1eed11610064578063db2e1eed14610768578063ec91f2a4146107a0578063f25efffc146107c7578063f2fde38b146107dc57600080fd5b8063af64dd30146106d5578063b1296a94146106f5578063b296024d14610715578063c0555d981461074857600080fd5b80639903cce6116100d15780639903cce61461066d578063a4d0a17e1461068d578063a94dd8a0146106a2578063abbfb786146106c257600080fd5b80638da5cb5b1461054b5780639149295614610569578063945c37cb1461059657600080fd5b80635112fabf1161016f578063715018a61161013e578063715018a6146103c25780637d9f6db5146103d75780638456cb591461050757806385317a291461051c57600080fd5b80635112fabf146103215780635c975abb14610341578063659dd2b4146103645780636dd83b5d1461037757600080fd5b80632de45f18116101ab5780632de45f181461026c57806336ebdb38146102b85780633f4ba83a146102d85780633fc8cef3146102ed57600080fd5b806309b85709146101d25780630ba4e9ea146102085780630fb5a6b41461022a575b600080fd5b3480156101de57600080fd5b506101f26101ed366004612746565b6107fc565b6040516101ff919061277f565b60405180910390f35b34801561021457600080fd5b5061022861022336600461281b565b610a4f565b005b34801561023657600080fd5b5061025e7f000000000000000000000000000000000000000000000000000000000000000081565b6040519081526020016101ff565b34801561027857600080fd5b506102a07f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020016101ff565b3480156102c457600080fd5b506102286102d336600461284e565b610b2d565b3480156102e457600080fd5b50610228610bfa565b3480156102f957600080fd5b506102a07f000000000000000000000000000000000000000000000000000000000000000081565b34801561032d57600080fd5b5061022861033c366004612869565b610c5a565b34801561034d57600080fd5b5060335460ff1660405190151581526020016101ff565b61022861037236600461288b565b610cd6565b34801561038357600080fd5b506103ad61039236600461288b565b600090815260cc602052604090206001015463ffffffff1690565b60405163ffffffff90911681526020016101ff565b3480156103ce57600080fd5b50610228610ce4565b3480156103e357600080fd5b506104946040805160c081018252600080825260208201819052918101829052606081018290526080810182905260a0810191909152506040805160c08101825260ca546001600160601b0381168252600160801b90046001600160801b0316602082015260cb5464ffffffffff80821693830193909352600160281b81049092166060820152600160501b82046001600160a01b03166080820152600160f01b90910460ff16151560a082015290565b6040516101ff919081516001600160601b031681526020808301516001600160801b03169082015260408083015164ffffffffff90811691830191909152606080840151909116908201526080808301516001600160a01b03169082015260a09182015115159181019190915260c00190565b34801561051357600080fd5b50610228610d18565b34801561052857600080fd5b506105336201518081565b60405166ffffffffffffff90911681526020016101ff565b34801561055757600080fd5b506097546001600160a01b03166102a0565b34801561057557600080fd5b5061058961058436600461288b565b610d4a565b6040516101ff91906128a4565b3480156105a257600080fd5b5060ca5460cb5461060a916001600160601b03811691600160601b820463ffffffff1691600160801b90046001600160801b03169064ffffffffff80821691600160281b810490911690600160501b81046001600160a01b031690600160f01b900460ff1687565b604080516001600160601b03909816885263ffffffff90961660208801526001600160801b039094169486019490945264ffffffffff91821660608601521660808401526001600160a01b0390911660a0830152151560c082015260e0016101ff565b34801561067957600080fd5b506102286106883660046128ff565b610f61565b34801561069957600080fd5b50610228611032565b3480156106ae57600080fd5b506102286106bd3660046129d4565b611083565b6102286106d0366004612ac8565b6111c0565b3480156106e157600080fd5b506101f26106f0366004612af4565b611602565b34801561070157600080fd5b506101f2610710366004612746565b61180b565b34801561072157600080fd5b5060c95461073690600160f81b900460ff1681565b60405160ff90911681526020016101ff565b34801561075457600080fd5b50610228610763366004612b24565b6119c9565b34801561077457600080fd5b5060c954610788906001600160c01b031681565b6040516001600160c01b0390911681526020016101ff565b3480156107ac57600080fd5b5060c95461053390600160c01b900466ffffffffffffff1681565b3480156107d357600080fd5b50610228611a41565b3480156107e857600080fd5b506102286107f7366004612b3f565b611a97565b60ca546060906001600160601b0316808511156108545760405162461bcd60e51b81526020600482015260116024820152707374617274496420746f6f206c6172676560781b60448201526064015b60405180910390fd5b61085e8582612b70565b610869906001612b83565b6001600160401b0381111561088057610880612942565b6040519080825280602002602001820160405280156108d957816020015b6040805160a08101825260008082526020808301829052928201819052606082018190526080820152825260001990920191018161089e5790505b50915060006108e661270a565b865b838111610a3757600081815260cc6020908152604091829020825160a081018452815463ffffffff8082168352600160201b8083046001600160401b031695840195909552600160601b9091046001600160a01b0316948201949094526001909101549283166060820152910460ff1615156080820152915085801561097957506001826000015163ffffffff1611155b610a2757838114801561099757506001826000015163ffffffff1611155b610a2757815163ffffffff168710610a37576040518060a00160405280836000015163ffffffff1681526020016109d18460200151611b2f565b815260200183604001516001600160a01b03168152602001828152602001836060015163ffffffff16815250858481518110610a0f57610a0f612b96565b602002602001018190525082610a2490612bac565b92505b610a3081612bac565b90506108e8565b508184511115610a45578184525b5050509392505050565b6097546001600160a01b03163314610a795760405162461bcd60e51b815260040161084b90612bc5565b6201518066ffffffffffffff82161115610acc5760405162461bcd60e51b815260206004820152601460248201527374696d6542756666657220746f6f206c6172676560601b604482015260640161084b565b60c9805466ffffffffffffff60c01b1916600160c01b66ffffffffffffff8416908102919091179091556040519081527f1b55d9f7002bda4490f467e326f22a4a847629c0f2d1ed421607d318d25b410d906020015b60405180910390a150565b6097546001600160a01b03163314610b575760405162461bcd60e51b815260040161084b90612bc5565b60008160ff1611610baa5760405162461bcd60e51b815260206004820152601960248201527f6d7573742062652067726561746572207468616e207a65726f00000000000000604482015260640161084b565b60c980546001600160f81b0316600160f81b60ff8416908102919091179091556040519081527fec5ccd96cc77b6219e9d44143df916af68fc169339ea7de5008ff15eae13450d90602001610b22565b6097546001600160a01b03163314610c245760405162461bcd60e51b815260040161084b90612bc5565b610c2c611b4e565b60cb5464ffffffffff161580610c4b575060cb54600160f01b900460ff165b15610c5857610c58611be1565b565b815b81811015610cd15761071c8111158015610c7e5750610c7c600a82612c10565b155b610cc957600081815260cc602052604081208054909163ffffffff9091169003610cc757805463ffffffff1916600190811782558101805464ff000000001916600160201b1790555b505b600101610c5c565b505050565b610ce18160006111c0565b50565b6097546001600160a01b03163314610d0e5760405162461bcd60e51b815260040161084b90612bc5565b610c586000611da0565b6097546001600160a01b03163314610d425760405162461bcd60e51b815260040161084b90612bc5565b610c58611df2565b60ca5460cb546060916001600160601b031690600160f01b900460ff16158015610d745750600081115b15610d8757610d84600182612b70565b90505b826001600160401b03811115610d9f57610d9f612942565b604051908082528060200260200182016040528015610dc8578160200160208202803683370190505b5091506000610dd561270a565b825b600081118015610de657508583105b15610f145761071c8111158015610e055750610e03600a82612c10565b155b610f0457600081815260cc6020908152604091829020825160a081018452815463ffffffff808216808452600160201b8084046001600160401b031696850196909652600160601b9092046001600160a01b03169583019590955260019283015494851660608301529290930460ff161515608084015291935011610ebb5760405162461bcd60e51b815260206004820152600c60248201526b4d697373696e67206461746160a01b604482015260640161084b565b60408201516001600160a01b031615610f0457610edb8260200151611b2f565b858481518110610eed57610eed612b96565b6020908102919091010152610f0183612bac565b92505b610f0d81612c24565b9050610dd7565b50818514610f595760405162461bcd60e51b81526020600482015260126024820152714e6f7420656e6f75676820686973746f727960701b604482015260640161084b565b505050919050565b600054610100900460ff1680610f7a575060005460ff16155b610f965760405162461bcd60e51b815260040161084b90612c3b565b600054610100900460ff16158015610fb8576000805461ffff19166101011790555b610fc0611e6d565b610fc8611ee8565b610fd0611f47565b610fd8611df2565b60c980546001600160c01b0386166001600160f81b031990911617600160c01b66ffffffffffffff861602176001600160f81b0316600160f81b60ff851602179055801561102c576000805461ff00191690555b50505050565b60335460ff1661107b5760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b604482015260640161084b565b610c58611fae565b6097546001600160a01b031633146110ad5760405162461bcd60e51b815260040161084b90612bc5565b60005b81518110156111bc57600060cc60008484815181106110d1576110d1612b96565b602002602001015160600151815260200190815260200160002090508282815181106110ff576110ff612b96565b602090810291909101015151815463ffffffff191663ffffffff90911617815582516111489084908490811061113757611137612b96565b60200260200101516020015161241e565b81546001600160401b0391909116600160201b026bffffffffffffffff0000000019909116178155825183908390811061118457611184612b96565b60209081029190910101516040015181546001600160a01b03909116600160601b026001600160601b039091161790556001016110b0565b5050565b6040805160e08101825260ca546001600160601b038116808352600160601b820463ffffffff166020840152600160801b9091046001600160801b03169282019290925260cb5464ffffffffff8082166060840152600160281b8204166080830152600160501b81046001600160a01b031660a0830152600160f01b900460ff908116151560c083015260c95491926001600160c01b03831692600160c01b810466ffffffffffffff1692600160f81b909104169086146112c35760405162461bcd60e51b815260206004820152601760248201527f4e6f756e206e6f7420757020666f722061756374696f6e000000000000000000604482015260640161084b565b836080015164ffffffffff16421061130f5760405162461bcd60e51b815260206004820152600f60248201526e105d58dd1a5bdb88195e1c1a5c9959608a1b604482015260640161084b565b826001600160c01b03163410156113685760405162461bcd60e51b815260206004820152601f60248201527f4d7573742073656e64206174206c656173742072657365727665507269636500604482015260640161084b565b60648160ff16856040015161137d9190612c89565b6113879190612cb4565b84604001516113969190612cda565b6001600160801b0316341015611416576040805162461bcd60e51b81526020600482015260248101919091527f4d7573742073656e64206d6f7265207468616e206c617374206269642062792060448201527f6d696e426964496e6372656d656e7450657263656e7461676520616d6f756e74606482015260840161084b565b60ca80546001600160601b0316600160601b63ffffffff8816026001600160801b0390811691909117600160801b349092169190910217905560cb80547fffff0000000000000000000000000000000000000000ffffffffffffffffffff1633600160501b02179055608084015160009066ffffffffffffff8416906114a490429064ffffffffff16612b70565b865160408051338152346020820152939092109183018290529092506001600160601b0316907f1159164c56f277e6fc99c11731bd380e0347deb969b75523398734c252706ea39060600160405180910390a263ffffffff86161561154b57845160405134815263ffffffff8816916001600160601b0316907f38e150a71033b4c9a3eeb9ebe568476f075a558e47171f3b5d715aa0cf6cd1b59060200160405180910390a35b80156115cd5761156466ffffffffffffff841642612b83565b64ffffffffff166080860181905260cb805469ffffffffff00000000001916600160281b830217905585516040519182526001600160601b0316907f6e912a3a9105bdd2af817ba5adc14e6c127c1035b5b648faa29ca0d58ab8ff4e9060200160405180910390a25b60a08501516001600160a01b038116156115f8576115f88187604001516001600160801b031661242e565b5050505050505050565b60ca5460cb546060916001600160601b031690600160f01b900460ff1615801561162c5750600081115b1561163f5761163c600182612b70565b90505b836001600160401b0381111561165757611657612942565b6040519080825280602002602001820160405280156116b057816020015b6040805160a0810182526000808252602080830182905292820181905260608201819052608082015282526000199092019101816116755790505b50915060006116bd61270a565b825b868310156117f557600081815260cc6020908152604091829020825160a081018452815463ffffffff8082168352600160201b8083046001600160401b031695840195909552600160601b9091046001600160a01b0316948201949094526001909101549283166060820152910460ff1615156080820152915085801561175157506001826000015163ffffffff1611155b156117615780156117f5576117e5565b6040518060a00160405280836000015163ffffffff1681526020016117898460200151611b2f565b815260200183604001516001600160a01b03168152602001828152602001836060015163ffffffff168152508584815181106117c7576117c7612b96565b6020026020010181905250826117dc90612bac565b925080156117f5575b6117ee81612c24565b90506116bf565b5081861115611802578184525b50505092915050565b60606118178484612b70565b6001600160401b0381111561182e5761182e612942565b60405190808252806020026020018201604052801561188757816020015b6040805160a08101825260008082526020808301829052928201819052606082018190526080820152825260001990920191018161184c5790505b509050600061189461270a565b855b858110156119b257600081815260cc6020908152604091829020825160a081018452815463ffffffff8082168352600160201b8083046001600160401b031695840195909552600160601b9091046001600160a01b0316948201949094526001909101549283166060820152910460ff1615156080820152915084801561192857506001826000015163ffffffff1611155b6119aa576040518060a00160405280836000015163ffffffff1681526020016119548460200151611b2f565b815260200183604001516001600160a01b03168152602001828152602001836060015163ffffffff1681525084848151811061199257611992612b96565b6020026020010181905250826119a790612bac565b92505b600101611896565b5081835111156119c0578183525b50509392505050565b6097546001600160a01b031633146119f35760405162461bcd60e51b815260040161084b90612bc5565b60c980546001600160c01b0319166001600160c01b0383169081179091556040519081527f6ab2e127d7fdf53b8f304e59d3aab5bfe97979f52a85479691a6fab27a28a6b290602001610b22565b60335460ff1615611a875760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b604482015260640161084b565b611a8f611fae565b610c58611be1565b6097546001600160a01b03163314611ac15760405162461bcd60e51b815260040161084b90612bc5565b6001600160a01b038116611b265760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b606482015260840161084b565b610ce181611da0565b6000611b486001600160401b0383166305f5e100612d01565b92915050565b60335460ff16611b975760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b604482015260640161084b565b6033805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316631249c58b6040518163ffffffff1660e01b81526004016020604051808303816000875af1925050508015611c5d575060408051601f3d908101601f19168201909252611c5a91810190612d18565b60015b611c9c57611c69612d31565b806308c379a003611c905750611c7d612d4d565b80611c885750611c92565b610ce1611df2565b505b3d6000803e3d6000fd5b426000611cc97f000000000000000000000000000000000000000000000000000000000000000083612dd6565b6040805160e0810182526001600160601b0386168082526000602080840182905283850182905264ffffffffff888116606086018190529087166080860181905260a0860184905260c09095019290925260ca9290925560cb805469ffffffffffffffffffff19168217600160281b8502177fff000000000000000000000000000000000000000000ffffffffffffffffffff16905583519081529081019190915291925084917fd6eddd1118d71820909c1197aa966dbc15ed6f508554252169cc3d5ccac756ca910160405180910390a2505050565b609780546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b60335460ff1615611e385760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b604482015260640161084b565b6033805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258611bc43390565b600054610100900460ff1680611e86575060005460ff16155b611ea25760405162461bcd60e51b815260040161084b90612c3b565b600054610100900460ff16158015611ec4576000805461ffff19166101011790555b611ecc612544565b611ed46125ae565b8015610ce1576000805461ff001916905550565b600054610100900460ff1680611f01575060005460ff16155b611f1d5760405162461bcd60e51b815260040161084b90612c3b565b600054610100900460ff16158015611f3f576000805461ffff19166101011790555b611ed4612623565b600054610100900460ff1680611f60575060005460ff16155b611f7c5760405162461bcd60e51b815260040161084b90612c3b565b600054610100900460ff16158015611f9e576000805461ffff19166101011790555b611fa6612544565b611ed4612693565b6040805160e08101825260ca546001600160601b0381168252600160601b810463ffffffff166020830152600160801b90046001600160801b03169181019190915260cb5464ffffffffff80821660608401819052600160281b83049091166080840152600160501b82046001600160a01b031660a0840152600160f01b90910460ff16151560c083015260000361207f5760405162461bcd60e51b815260206004820152601460248201527320bab1ba34b7b7103430b9b713ba103132b3bab760611b604482015260640161084b565b8060c00151156120d15760405162461bcd60e51b815260206004820181905260248201527f41756374696f6e2068617320616c7265616479206265656e20736574746c6564604482015260640161084b565b806080015164ffffffffff1642101561212c5760405162461bcd60e51b815260206004820152601860248201527f41756374696f6e206861736e277420636f6d706c657465640000000000000000604482015260640161084b565b60cb805460ff60f01b1916600160f01b17905560a08101516001600160a01b03166121db578051604051630852cd8d60e31b81526001600160601b0390911660048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906342966c6890602401600060405180830381600087803b1580156121be57600080fd5b505af11580156121d2573d6000803e3d6000fd5b50505050612276565b60a081015181516040516323b872dd60e01b81523060048201526001600160a01b0392831660248201526001600160601b0390911660448201527f0000000000000000000000000000000000000000000000000000000000000000909116906323b872dd90606401600060405180830381600087803b15801561225d57600080fd5b505af1158015612271573d6000803e3d6000fd5b505050505b60408101516001600160801b0316156122b1576122b161229e6097546001600160a01b031690565b82604001516001600160801b031661242e565b80516001600160601b0316600090815260cc602052604090819020805463ffffffff19164263ffffffff16178155908201516122f5906001600160801b031661241e565b815460a08401516001600160a01b0316600160601b026001600160601b036001600160401b0393909316600160201b029290921663ffffffff918216179190911782556020830151161561236457602082015160018201805463ffffffff191663ffffffff9092169190911790555b815160a083015160408085015181516001600160a01b0390931683526001600160801b031660208301526001600160601b03909216917fc9f72b276a388619c6d185d146697036241880c36654b1a3ffdad07c24038d99910160405180910390a2602082015163ffffffff16156111bc57816020015163ffffffff1682600001516001600160601b03167ff445afb110f5e782fc78bf23e7066d3c5a95f7b57bd25fb718a29ad0287db2b960405160405180910390a35050565b6000611b486305f5e10083612df4565b61243882826126f3565b6111bc577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b15801561249757600080fd5b505af11580156124ab573d6000803e3d6000fd5b505060405163a9059cbb60e01b81526001600160a01b038681166004830152602482018690527f000000000000000000000000000000000000000000000000000000000000000016935063a9059cbb925060440190506020604051808303816000875af1158015612520573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cd19190612e08565b600054610100900460ff168061255d575060005460ff16155b6125795760405162461bcd60e51b815260040161084b90612c3b565b600054610100900460ff16158015611ed4576000805461ffff19166101011790558015610ce1576000805461ff001916905550565b600054610100900460ff16806125c7575060005460ff16155b6125e35760405162461bcd60e51b815260040161084b90612c3b565b600054610100900460ff16158015612605576000805461ffff19166101011790555b6033805460ff191690558015610ce1576000805461ff001916905550565b600054610100900460ff168061263c575060005460ff16155b6126585760405162461bcd60e51b815260040161084b90612c3b565b600054610100900460ff1615801561267a576000805461ffff19166101011790555b60016065558015610ce1576000805461ff001916905550565b600054610100900460ff16806126ac575060005460ff16155b6126c85760405162461bcd60e51b815260040161084b90612c3b565b600054610100900460ff161580156126ea576000805461ffff19166101011790555b611ed433611da0565b6000806000806000808688617530f1949350505050565b6040805160a08101825260008082526020820181905291810182905260608101829052608081019190915290565b8015158114610ce157600080fd5b60008060006060848603121561275b57600080fd5b8335925060208401359150604084013561277481612738565b809150509250925092565b602080825282518282018190526000919060409081850190868401855b828110156127f2578151805163ffffffff90811686528782015188870152868201516001600160a01b03168787015260608083015190870152608091820151169085015260a0909301929085019060010161279c565b5091979650505050505050565b803566ffffffffffffff8116811461281657600080fd5b919050565b60006020828403121561282d57600080fd5b612836826127ff565b9392505050565b803560ff8116811461281657600080fd5b60006020828403121561286057600080fd5b6128368261283d565b6000806040838503121561287c57600080fd5b50508035926020909101359150565b60006020828403121561289d57600080fd5b5035919050565b6020808252825182820181905260009190848201906040850190845b818110156128dc578351835292840192918401916001016128c0565b50909695505050505050565b80356001600160c01b038116811461281657600080fd5b60008060006060848603121561291457600080fd5b61291d846128e8565b925061292b602085016127ff565b91506129396040850161283d565b90509250925092565b634e487b7160e01b600052604160045260246000fd5b608081018181106001600160401b038211171561297757612977612942565b60405250565b601f8201601f191681016001600160401b03811182821017156129a2576129a2612942565b6040525050565b803563ffffffff8116811461281657600080fd5b80356001600160a01b038116811461281657600080fd5b600060208083850312156129e757600080fd5b82356001600160401b03808211156129fe57600080fd5b818501915085601f830112612a1257600080fd5b813581811115612a2457612a24612942565b60409150604051612a3a858360051b018261297d565b81815260079190911b830184019084810188831115612a5857600080fd5b938501935b82851015612abc576080858a031215612a765760008081fd5b8351612a8181612958565b612a8a866129a9565b81528686013587820152612a9f8587016129bd565b818601526060868101359082015281526080909401938501612a5d565b50979650505050505050565b60008060408385031215612adb57600080fd5b82359150612aeb602084016129a9565b90509250929050565b60008060408385031215612b0757600080fd5b823591506020830135612b1981612738565b809150509250929050565b600060208284031215612b3657600080fd5b612836826128e8565b600060208284031215612b5157600080fd5b612836826129bd565b634e487b7160e01b600052601160045260246000fd5b81810381811115611b4857611b48612b5a565b80820180821115611b4857611b48612b5a565b634e487b7160e01b600052603260045260246000fd5b600060018201612bbe57612bbe612b5a565b5060010190565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b634e487b7160e01b600052601260045260246000fd5b600082612c1f57612c1f612bfa565b500690565b600081612c3357612c33612b5a565b506000190190565b6020808252602e908201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160408201526d191e481a5b9a5d1a585b1a5e995960921b606082015260800190565b6001600160801b03818116838216028082169190828114612cac57612cac612b5a565b505092915050565b60006001600160801b0380841680612cce57612cce612bfa565b92169190910492915050565b6001600160801b03818116838216019080821115612cfa57612cfa612b5a565b5092915050565b8082028115828204841417611b4857611b48612b5a565b600060208284031215612d2a57600080fd5b5051919050565b600060033d1115612d4a5760046000803e5060005160e01c5b90565b600060443d1015612d5b5790565b6040516003193d81016004833e81513d6001600160401b038160248401118184111715612d8a57505050505090565b8285019150815181811115612da25750505050505090565b843d8701016020828501011115612dbc5750505050505090565b612dcb6020828601018761297d565b509095945050505050565b64ffffffffff818116838216019080821115612cfa57612cfa612b5a565b600082612e0357612e03612bfa565b500490565b600060208284031215612e1a57600080fd5b81516128368161273856fea26469706673582212204eed286559142f12f42055a0eba0e732348e19053404b823817c2b809c389e7864736f6c634300081700330000000000000000000000009c8ff314c9bc7f6e59a9d9225fb22946427edc03000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000000000000015180", + "nonce": "0x1", + "chainId": "0x1", + "accessList": null, + "type": null + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x56b39dd0269cbf457ee0d585c90d4c2c9281493834e88993fb94d3dc6ddc6fa0", + "transactionType": "CREATE", + "contractName": "NounsAuctionHousePreV2Migration", + "contractAddress": "0x714f5039c2ca1641b8823469a852513bf6018fa4", + "function": null, + "arguments": null, + "transaction": { + "from": "0x918895f466eb3cd5fb181626f8e1b2fd8a9d5192", + "to": null, + "gas": "0x92cc9", + "value": "0x0", + "input": "0x608060405234801561001057600080fd5b50610769806100206000396000f3fe608060405234801561001057600080fd5b50600436106100575760003560e01c80635c975abb1461005c578063715018a6146100775780638da5cb5b146100815780638fd3ab801461009c578063f2fde38b146100a4575b600080fd5b60335460ff1660405190151581526020015b60405180910390f35b61007f6100b7565b005b6097546040516001600160a01b03909116815260200161006e565b61007f6100f6565b61007f6100b23660046106ce565b6105e1565b6097546001600160a01b031633146100ea5760405162461bcd60e51b81526004016100e1906106fe565b60405180910390fd5b6100f4600061067c565b565b6097546001600160a01b031633146101205760405162461bcd60e51b81526004016100e1906106fe565b600060c99050600060c990506000826040518060e00160405290816000820160009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b031681526020016001820160009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b0316815260200160028201548152602001600382015481526020016004820160009054906101000a900460ff1660ff1660ff16815260200160058201548152602001600682016040518060c0016040529081600082015481526020016001820154815260200160028201548152602001600382015481526020016004820160009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b031681526020016004820160149054906101000a900460ff16151515158152505081525050905060008360000160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060008360010160006101000a8154816001600160a01b0302191690836001600160a01b03160217905550600083600201819055506000836003018190555060008360040160006101000a81548160ff021916908360ff160217905550600083600501819055506040518060c001604052806000815260200160008152602001600081526020016000815260200160006001600160a01b0316815260200160001515815250836006016000820151816000015560208201518160010155604082015181600201556060820151816003015560808201518160040160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060a08201518160040160146101000a81548160ff02191690831515021790555090505080606001518260000160006101000a8154816001600160c01b0302191690836001600160c01b0316021790555080604001518260000160186101000a81548166ffffffffffffff021916908366ffffffffffffff160217905550806080015182600001601f6101000a81548160ff021916908360ff1602179055506040518060e001604052808260c00151600001516001600160601b03168152602001600063ffffffff1681526020018260c00151602001516001600160801b031681526020018260c001516040015164ffffffffff1681526020018260c001516060015164ffffffffff1681526020018260c00151608001516001600160a01b031681526020018260c0015160a0015115158152508260010160008201518160000160006101000a8154816001600160601b0302191690836001600160601b03160217905550602082015181600001600c6101000a81548163ffffffff021916908363ffffffff16021790555060408201518160000160106101000a8154816001600160801b0302191690836001600160801b0316021790555060608201518160010160006101000a81548164ffffffffff021916908364ffffffffff16021790555060808201518160010160056101000a81548164ffffffffff021916908364ffffffffff16021790555060a082015181600101600a6101000a8154816001600160a01b0302191690836001600160a01b0316021790555060c082015181600101601e6101000a81548160ff021916908315150217905550905050505050565b6097546001600160a01b0316331461060b5760405162461bcd60e51b81526004016100e1906106fe565b6001600160a01b0381166106705760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084016100e1565b6106798161067c565b50565b609780546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6000602082840312156106e057600080fd5b81356001600160a01b03811681146106f757600080fd5b9392505050565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260408201526060019056fea2646970667358221220eccf365de37364bac882a745bfa92868d893629bdbb6d40821d4aa7ab61698bd64736f6c63430008170033", + "nonce": "0x2", + "chainId": "0x1", + "accessList": null, + "type": null + }, + "additionalContracts": [], + "isFixedGasLimit": false + } + ], + "receipts": [ + { + "status": "0x1", + "cumulativeGasUsed": "0x939d0e", + "logs": [], + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "type": "0x2", + "transactionHash": "0xc5e5b47fd700d2a4471389f4c1ee759c9a82d77eefdbb683283a4d91c59f1fa6", + "transactionIndex": "0x5a", + "blockHash": "0xcdb00fa8a29f83a5f094d01715eef5298daaa9ee2d22b20799860312087b9f8c", + "blockNumber": "0x12cdc58", + "gasUsed": "0x2855fe", + "effectiveGasPrice": "0x1e176696d", + "from": "0x918895f466eb3cd5fb181626f8e1b2fd8a9d5192", + "to": null, + "contractAddress": "0x2fdadd994b1edefd19744f00d1afe85045a31561" + }, + { + "status": "0x1", + "cumulativeGasUsed": "0x9aac4a", + "logs": [], + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "type": "0x2", + "transactionHash": "0x56b39dd0269cbf457ee0d585c90d4c2c9281493834e88993fb94d3dc6ddc6fa0", + "transactionIndex": "0x5b", + "blockHash": "0xcdb00fa8a29f83a5f094d01715eef5298daaa9ee2d22b20799860312087b9f8c", + "blockNumber": "0x12cdc58", + "gasUsed": "0x70f3c", + "effectiveGasPrice": "0x1e176696d", + "from": "0x918895f466eb3cd5fb181626f8e1b2fd8a9d5192", + "to": null, + "contractAddress": "0x714f5039c2ca1641b8823469a852513bf6018fa4" + } + ], + "libraries": [], + "pending": [], + "returns": { + "newLogic": { + "internal_type": "contract NounsAuctionHouseV2", + "value": "0x2FDAdd994b1eDEfD19744F00d1Afe85045A31561" + }, + "migratorLogic": { + "internal_type": "contract NounsAuctionHousePreV2Migration", + "value": "0x714f5039C2cA1641b8823469a852513bF6018fa4" + } + }, + "timestamp": 1713864636, + "chain": 1, + "commit": "82b8d911" +} \ No newline at end of file diff --git a/packages/nouns-contracts/broadcast/DeployAuctionHouseV2Sepolia.s.sol/11155111/run-1713863057.json b/packages/nouns-contracts/broadcast/DeployAuctionHouseV2Sepolia.s.sol/11155111/run-1713863057.json new file mode 100644 index 0000000000..7ceabe9f73 --- /dev/null +++ b/packages/nouns-contracts/broadcast/DeployAuctionHouseV2Sepolia.s.sol/11155111/run-1713863057.json @@ -0,0 +1,99 @@ +{ + "transactions": [ + { + "hash": "0xdbcdc80fa2440517a1cef2c379a7c181aa3d692b6217c73a848bd39193e38544", + "transactionType": "CREATE", + "contractName": "NounsAuctionHouseV2", + "contractAddress": "0xbb4f08516268be9bc43978edf50ed8a1aceeae26", + "function": null, + "arguments": [ + "0x054183Db3bE7E1AE513DBb0F26288084a2337531", + "0xfFf9976782d46CC05630D1f6eBAb18b2324d6B14", + "120" + ], + "transaction": { + "from": "0xad36c32f3c28a9214adcf50a09998de1d3b0ee06", + "to": null, + "gas": "0x346bb7", + "value": "0x0", + "input": "0x60e06040523480156200001157600080fd5b506040516200302438038062003024833981016040819052620000349162000127565b600054610100900460ff16806200004e575060005460ff16155b620000b65760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b606482015260840160405180910390fd5b600054610100900460ff16158015620000d9576000805461ffff19166101011790555b6001600160a01b03808516608052831660a05260c0829052801562000104576000805461ff00191690555b505050506200016f565b6001600160a01b03811681146200012457600080fd5b50565b6000806000606084860312156200013d57600080fd5b83516200014a816200010e565b60208501519093506200015d816200010e565b80925050604084015190509250925092565b60805160a05160c051612e5b620001c96000396000818161023c0152611ca40152600081816102ff0152818161243e01526124d301526000818161027e01528181611be30152818161217201526122170152612e5b6000f3fe6080604052600436106101cd5760003560e01c80638da5cb5b116100f7578063af64dd3011610095578063db2e1eed11610064578063db2e1eed14610768578063ec91f2a4146107a0578063f25efffc146107c7578063f2fde38b146107dc57600080fd5b8063af64dd30146106d5578063b1296a94146106f5578063b296024d14610715578063c0555d981461074857600080fd5b80639903cce6116100d15780639903cce61461066d578063a4d0a17e1461068d578063a94dd8a0146106a2578063abbfb786146106c257600080fd5b80638da5cb5b1461054b5780639149295614610569578063945c37cb1461059657600080fd5b80635112fabf1161016f578063715018a61161013e578063715018a6146103c25780637d9f6db5146103d75780638456cb591461050757806385317a291461051c57600080fd5b80635112fabf146103215780635c975abb14610341578063659dd2b4146103645780636dd83b5d1461037757600080fd5b80632de45f18116101ab5780632de45f181461026c57806336ebdb38146102b85780633f4ba83a146102d85780633fc8cef3146102ed57600080fd5b806309b85709146101d25780630ba4e9ea146102085780630fb5a6b41461022a575b600080fd5b3480156101de57600080fd5b506101f26101ed366004612746565b6107fc565b6040516101ff919061277f565b60405180910390f35b34801561021457600080fd5b5061022861022336600461281b565b610a4f565b005b34801561023657600080fd5b5061025e7f000000000000000000000000000000000000000000000000000000000000000081565b6040519081526020016101ff565b34801561027857600080fd5b506102a07f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020016101ff565b3480156102c457600080fd5b506102286102d336600461284e565b610b2d565b3480156102e457600080fd5b50610228610bfa565b3480156102f957600080fd5b506102a07f000000000000000000000000000000000000000000000000000000000000000081565b34801561032d57600080fd5b5061022861033c366004612869565b610c5a565b34801561034d57600080fd5b5060335460ff1660405190151581526020016101ff565b61022861037236600461288b565b610cd6565b34801561038357600080fd5b506103ad61039236600461288b565b600090815260cc602052604090206001015463ffffffff1690565b60405163ffffffff90911681526020016101ff565b3480156103ce57600080fd5b50610228610ce4565b3480156103e357600080fd5b506104946040805160c081018252600080825260208201819052918101829052606081018290526080810182905260a0810191909152506040805160c08101825260ca546001600160601b0381168252600160801b90046001600160801b0316602082015260cb5464ffffffffff80821693830193909352600160281b81049092166060820152600160501b82046001600160a01b03166080820152600160f01b90910460ff16151560a082015290565b6040516101ff919081516001600160601b031681526020808301516001600160801b03169082015260408083015164ffffffffff90811691830191909152606080840151909116908201526080808301516001600160a01b03169082015260a09182015115159181019190915260c00190565b34801561051357600080fd5b50610228610d18565b34801561052857600080fd5b506105336201518081565b60405166ffffffffffffff90911681526020016101ff565b34801561055757600080fd5b506097546001600160a01b03166102a0565b34801561057557600080fd5b5061058961058436600461288b565b610d4a565b6040516101ff91906128a4565b3480156105a257600080fd5b5060ca5460cb5461060a916001600160601b03811691600160601b820463ffffffff1691600160801b90046001600160801b03169064ffffffffff80821691600160281b810490911690600160501b81046001600160a01b031690600160f01b900460ff1687565b604080516001600160601b03909816885263ffffffff90961660208801526001600160801b039094169486019490945264ffffffffff91821660608601521660808401526001600160a01b0390911660a0830152151560c082015260e0016101ff565b34801561067957600080fd5b506102286106883660046128ff565b610f61565b34801561069957600080fd5b50610228611032565b3480156106ae57600080fd5b506102286106bd3660046129d4565b611083565b6102286106d0366004612ac8565b6111c0565b3480156106e157600080fd5b506101f26106f0366004612af4565b611602565b34801561070157600080fd5b506101f2610710366004612746565b61180b565b34801561072157600080fd5b5060c95461073690600160f81b900460ff1681565b60405160ff90911681526020016101ff565b34801561075457600080fd5b50610228610763366004612b24565b6119c9565b34801561077457600080fd5b5060c954610788906001600160c01b031681565b6040516001600160c01b0390911681526020016101ff565b3480156107ac57600080fd5b5060c95461053390600160c01b900466ffffffffffffff1681565b3480156107d357600080fd5b50610228611a41565b3480156107e857600080fd5b506102286107f7366004612b3f565b611a97565b60ca546060906001600160601b0316808511156108545760405162461bcd60e51b81526020600482015260116024820152707374617274496420746f6f206c6172676560781b60448201526064015b60405180910390fd5b61085e8582612b70565b610869906001612b83565b6001600160401b0381111561088057610880612942565b6040519080825280602002602001820160405280156108d957816020015b6040805160a08101825260008082526020808301829052928201819052606082018190526080820152825260001990920191018161089e5790505b50915060006108e661270a565b865b838111610a3757600081815260cc6020908152604091829020825160a081018452815463ffffffff8082168352600160201b8083046001600160401b031695840195909552600160601b9091046001600160a01b0316948201949094526001909101549283166060820152910460ff1615156080820152915085801561097957506001826000015163ffffffff1611155b610a2757838114801561099757506001826000015163ffffffff1611155b610a2757815163ffffffff168710610a37576040518060a00160405280836000015163ffffffff1681526020016109d18460200151611b2f565b815260200183604001516001600160a01b03168152602001828152602001836060015163ffffffff16815250858481518110610a0f57610a0f612b96565b602002602001018190525082610a2490612bac565b92505b610a3081612bac565b90506108e8565b508184511115610a45578184525b5050509392505050565b6097546001600160a01b03163314610a795760405162461bcd60e51b815260040161084b90612bc5565b6201518066ffffffffffffff82161115610acc5760405162461bcd60e51b815260206004820152601460248201527374696d6542756666657220746f6f206c6172676560601b604482015260640161084b565b60c9805466ffffffffffffff60c01b1916600160c01b66ffffffffffffff8416908102919091179091556040519081527f1b55d9f7002bda4490f467e326f22a4a847629c0f2d1ed421607d318d25b410d906020015b60405180910390a150565b6097546001600160a01b03163314610b575760405162461bcd60e51b815260040161084b90612bc5565b60008160ff1611610baa5760405162461bcd60e51b815260206004820152601960248201527f6d7573742062652067726561746572207468616e207a65726f00000000000000604482015260640161084b565b60c980546001600160f81b0316600160f81b60ff8416908102919091179091556040519081527fec5ccd96cc77b6219e9d44143df916af68fc169339ea7de5008ff15eae13450d90602001610b22565b6097546001600160a01b03163314610c245760405162461bcd60e51b815260040161084b90612bc5565b610c2c611b4e565b60cb5464ffffffffff161580610c4b575060cb54600160f01b900460ff165b15610c5857610c58611be1565b565b815b81811015610cd15761071c8111158015610c7e5750610c7c600a82612c10565b155b610cc957600081815260cc602052604081208054909163ffffffff9091169003610cc757805463ffffffff1916600190811782558101805464ff000000001916600160201b1790555b505b600101610c5c565b505050565b610ce18160006111c0565b50565b6097546001600160a01b03163314610d0e5760405162461bcd60e51b815260040161084b90612bc5565b610c586000611da0565b6097546001600160a01b03163314610d425760405162461bcd60e51b815260040161084b90612bc5565b610c58611df2565b60ca5460cb546060916001600160601b031690600160f01b900460ff16158015610d745750600081115b15610d8757610d84600182612b70565b90505b826001600160401b03811115610d9f57610d9f612942565b604051908082528060200260200182016040528015610dc8578160200160208202803683370190505b5091506000610dd561270a565b825b600081118015610de657508583105b15610f145761071c8111158015610e055750610e03600a82612c10565b155b610f0457600081815260cc6020908152604091829020825160a081018452815463ffffffff808216808452600160201b8084046001600160401b031696850196909652600160601b9092046001600160a01b03169583019590955260019283015494851660608301529290930460ff161515608084015291935011610ebb5760405162461bcd60e51b815260206004820152600c60248201526b4d697373696e67206461746160a01b604482015260640161084b565b60408201516001600160a01b031615610f0457610edb8260200151611b2f565b858481518110610eed57610eed612b96565b6020908102919091010152610f0183612bac565b92505b610f0d81612c24565b9050610dd7565b50818514610f595760405162461bcd60e51b81526020600482015260126024820152714e6f7420656e6f75676820686973746f727960701b604482015260640161084b565b505050919050565b600054610100900460ff1680610f7a575060005460ff16155b610f965760405162461bcd60e51b815260040161084b90612c3b565b600054610100900460ff16158015610fb8576000805461ffff19166101011790555b610fc0611e6d565b610fc8611ee8565b610fd0611f47565b610fd8611df2565b60c980546001600160c01b0386166001600160f81b031990911617600160c01b66ffffffffffffff861602176001600160f81b0316600160f81b60ff851602179055801561102c576000805461ff00191690555b50505050565b60335460ff1661107b5760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b604482015260640161084b565b610c58611fae565b6097546001600160a01b031633146110ad5760405162461bcd60e51b815260040161084b90612bc5565b60005b81518110156111bc57600060cc60008484815181106110d1576110d1612b96565b602002602001015160600151815260200190815260200160002090508282815181106110ff576110ff612b96565b602090810291909101015151815463ffffffff191663ffffffff90911617815582516111489084908490811061113757611137612b96565b60200260200101516020015161241e565b81546001600160401b0391909116600160201b026bffffffffffffffff0000000019909116178155825183908390811061118457611184612b96565b60209081029190910101516040015181546001600160a01b03909116600160601b026001600160601b039091161790556001016110b0565b5050565b6040805160e08101825260ca546001600160601b038116808352600160601b820463ffffffff166020840152600160801b9091046001600160801b03169282019290925260cb5464ffffffffff8082166060840152600160281b8204166080830152600160501b81046001600160a01b031660a0830152600160f01b900460ff908116151560c083015260c95491926001600160c01b03831692600160c01b810466ffffffffffffff1692600160f81b909104169086146112c35760405162461bcd60e51b815260206004820152601760248201527f4e6f756e206e6f7420757020666f722061756374696f6e000000000000000000604482015260640161084b565b836080015164ffffffffff16421061130f5760405162461bcd60e51b815260206004820152600f60248201526e105d58dd1a5bdb88195e1c1a5c9959608a1b604482015260640161084b565b826001600160c01b03163410156113685760405162461bcd60e51b815260206004820152601f60248201527f4d7573742073656e64206174206c656173742072657365727665507269636500604482015260640161084b565b60648160ff16856040015161137d9190612c89565b6113879190612cb4565b84604001516113969190612cda565b6001600160801b0316341015611416576040805162461bcd60e51b81526020600482015260248101919091527f4d7573742073656e64206d6f7265207468616e206c617374206269642062792060448201527f6d696e426964496e6372656d656e7450657263656e7461676520616d6f756e74606482015260840161084b565b60ca80546001600160601b0316600160601b63ffffffff8816026001600160801b0390811691909117600160801b349092169190910217905560cb80547fffff0000000000000000000000000000000000000000ffffffffffffffffffff1633600160501b02179055608084015160009066ffffffffffffff8416906114a490429064ffffffffff16612b70565b865160408051338152346020820152939092109183018290529092506001600160601b0316907f1159164c56f277e6fc99c11731bd380e0347deb969b75523398734c252706ea39060600160405180910390a263ffffffff86161561154b57845160405134815263ffffffff8816916001600160601b0316907f38e150a71033b4c9a3eeb9ebe568476f075a558e47171f3b5d715aa0cf6cd1b59060200160405180910390a35b80156115cd5761156466ffffffffffffff841642612b83565b64ffffffffff166080860181905260cb805469ffffffffff00000000001916600160281b830217905585516040519182526001600160601b0316907f6e912a3a9105bdd2af817ba5adc14e6c127c1035b5b648faa29ca0d58ab8ff4e9060200160405180910390a25b60a08501516001600160a01b038116156115f8576115f88187604001516001600160801b031661242e565b5050505050505050565b60ca5460cb546060916001600160601b031690600160f01b900460ff1615801561162c5750600081115b1561163f5761163c600182612b70565b90505b836001600160401b0381111561165757611657612942565b6040519080825280602002602001820160405280156116b057816020015b6040805160a0810182526000808252602080830182905292820181905260608201819052608082015282526000199092019101816116755790505b50915060006116bd61270a565b825b868310156117f557600081815260cc6020908152604091829020825160a081018452815463ffffffff8082168352600160201b8083046001600160401b031695840195909552600160601b9091046001600160a01b0316948201949094526001909101549283166060820152910460ff1615156080820152915085801561175157506001826000015163ffffffff1611155b156117615780156117f5576117e5565b6040518060a00160405280836000015163ffffffff1681526020016117898460200151611b2f565b815260200183604001516001600160a01b03168152602001828152602001836060015163ffffffff168152508584815181106117c7576117c7612b96565b6020026020010181905250826117dc90612bac565b925080156117f5575b6117ee81612c24565b90506116bf565b5081861115611802578184525b50505092915050565b60606118178484612b70565b6001600160401b0381111561182e5761182e612942565b60405190808252806020026020018201604052801561188757816020015b6040805160a08101825260008082526020808301829052928201819052606082018190526080820152825260001990920191018161184c5790505b509050600061189461270a565b855b858110156119b257600081815260cc6020908152604091829020825160a081018452815463ffffffff8082168352600160201b8083046001600160401b031695840195909552600160601b9091046001600160a01b0316948201949094526001909101549283166060820152910460ff1615156080820152915084801561192857506001826000015163ffffffff1611155b6119aa576040518060a00160405280836000015163ffffffff1681526020016119548460200151611b2f565b815260200183604001516001600160a01b03168152602001828152602001836060015163ffffffff1681525084848151811061199257611992612b96565b6020026020010181905250826119a790612bac565b92505b600101611896565b5081835111156119c0578183525b50509392505050565b6097546001600160a01b031633146119f35760405162461bcd60e51b815260040161084b90612bc5565b60c980546001600160c01b0319166001600160c01b0383169081179091556040519081527f6ab2e127d7fdf53b8f304e59d3aab5bfe97979f52a85479691a6fab27a28a6b290602001610b22565b60335460ff1615611a875760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b604482015260640161084b565b611a8f611fae565b610c58611be1565b6097546001600160a01b03163314611ac15760405162461bcd60e51b815260040161084b90612bc5565b6001600160a01b038116611b265760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b606482015260840161084b565b610ce181611da0565b6000611b486001600160401b0383166305f5e100612d01565b92915050565b60335460ff16611b975760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b604482015260640161084b565b6033805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316631249c58b6040518163ffffffff1660e01b81526004016020604051808303816000875af1925050508015611c5d575060408051601f3d908101601f19168201909252611c5a91810190612d18565b60015b611c9c57611c69612d31565b806308c379a003611c905750611c7d612d4d565b80611c885750611c92565b610ce1611df2565b505b3d6000803e3d6000fd5b426000611cc97f000000000000000000000000000000000000000000000000000000000000000083612dd6565b6040805160e0810182526001600160601b0386168082526000602080840182905283850182905264ffffffffff888116606086018190529087166080860181905260a0860184905260c09095019290925260ca9290925560cb805469ffffffffffffffffffff19168217600160281b8502177fff000000000000000000000000000000000000000000ffffffffffffffffffff16905583519081529081019190915291925084917fd6eddd1118d71820909c1197aa966dbc15ed6f508554252169cc3d5ccac756ca910160405180910390a2505050565b609780546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b60335460ff1615611e385760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b604482015260640161084b565b6033805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258611bc43390565b600054610100900460ff1680611e86575060005460ff16155b611ea25760405162461bcd60e51b815260040161084b90612c3b565b600054610100900460ff16158015611ec4576000805461ffff19166101011790555b611ecc612544565b611ed46125ae565b8015610ce1576000805461ff001916905550565b600054610100900460ff1680611f01575060005460ff16155b611f1d5760405162461bcd60e51b815260040161084b90612c3b565b600054610100900460ff16158015611f3f576000805461ffff19166101011790555b611ed4612623565b600054610100900460ff1680611f60575060005460ff16155b611f7c5760405162461bcd60e51b815260040161084b90612c3b565b600054610100900460ff16158015611f9e576000805461ffff19166101011790555b611fa6612544565b611ed4612693565b6040805160e08101825260ca546001600160601b0381168252600160601b810463ffffffff166020830152600160801b90046001600160801b03169181019190915260cb5464ffffffffff80821660608401819052600160281b83049091166080840152600160501b82046001600160a01b031660a0840152600160f01b90910460ff16151560c083015260000361207f5760405162461bcd60e51b815260206004820152601460248201527320bab1ba34b7b7103430b9b713ba103132b3bab760611b604482015260640161084b565b8060c00151156120d15760405162461bcd60e51b815260206004820181905260248201527f41756374696f6e2068617320616c7265616479206265656e20736574746c6564604482015260640161084b565b806080015164ffffffffff1642101561212c5760405162461bcd60e51b815260206004820152601860248201527f41756374696f6e206861736e277420636f6d706c657465640000000000000000604482015260640161084b565b60cb805460ff60f01b1916600160f01b17905560a08101516001600160a01b03166121db578051604051630852cd8d60e31b81526001600160601b0390911660048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906342966c6890602401600060405180830381600087803b1580156121be57600080fd5b505af11580156121d2573d6000803e3d6000fd5b50505050612276565b60a081015181516040516323b872dd60e01b81523060048201526001600160a01b0392831660248201526001600160601b0390911660448201527f0000000000000000000000000000000000000000000000000000000000000000909116906323b872dd90606401600060405180830381600087803b15801561225d57600080fd5b505af1158015612271573d6000803e3d6000fd5b505050505b60408101516001600160801b0316156122b1576122b161229e6097546001600160a01b031690565b82604001516001600160801b031661242e565b80516001600160601b0316600090815260cc602052604090819020805463ffffffff19164263ffffffff16178155908201516122f5906001600160801b031661241e565b815460a08401516001600160a01b0316600160601b026001600160601b036001600160401b0393909316600160201b029290921663ffffffff918216179190911782556020830151161561236457602082015160018201805463ffffffff191663ffffffff9092169190911790555b815160a083015160408085015181516001600160a01b0390931683526001600160801b031660208301526001600160601b03909216917fc9f72b276a388619c6d185d146697036241880c36654b1a3ffdad07c24038d99910160405180910390a2602082015163ffffffff16156111bc57816020015163ffffffff1682600001516001600160601b03167ff445afb110f5e782fc78bf23e7066d3c5a95f7b57bd25fb718a29ad0287db2b960405160405180910390a35050565b6000611b486305f5e10083612df4565b61243882826126f3565b6111bc577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b15801561249757600080fd5b505af11580156124ab573d6000803e3d6000fd5b505060405163a9059cbb60e01b81526001600160a01b038681166004830152602482018690527f000000000000000000000000000000000000000000000000000000000000000016935063a9059cbb925060440190506020604051808303816000875af1158015612520573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cd19190612e08565b600054610100900460ff168061255d575060005460ff16155b6125795760405162461bcd60e51b815260040161084b90612c3b565b600054610100900460ff16158015611ed4576000805461ffff19166101011790558015610ce1576000805461ff001916905550565b600054610100900460ff16806125c7575060005460ff16155b6125e35760405162461bcd60e51b815260040161084b90612c3b565b600054610100900460ff16158015612605576000805461ffff19166101011790555b6033805460ff191690558015610ce1576000805461ff001916905550565b600054610100900460ff168061263c575060005460ff16155b6126585760405162461bcd60e51b815260040161084b90612c3b565b600054610100900460ff1615801561267a576000805461ffff19166101011790555b60016065558015610ce1576000805461ff001916905550565b600054610100900460ff16806126ac575060005460ff16155b6126c85760405162461bcd60e51b815260040161084b90612c3b565b600054610100900460ff161580156126ea576000805461ffff19166101011790555b611ed433611da0565b6000806000806000808688617530f1949350505050565b6040805160a08101825260008082526020820181905291810182905260608101829052608081019190915290565b8015158114610ce157600080fd5b60008060006060848603121561275b57600080fd5b8335925060208401359150604084013561277481612738565b809150509250925092565b602080825282518282018190526000919060409081850190868401855b828110156127f2578151805163ffffffff90811686528782015188870152868201516001600160a01b03168787015260608083015190870152608091820151169085015260a0909301929085019060010161279c565b5091979650505050505050565b803566ffffffffffffff8116811461281657600080fd5b919050565b60006020828403121561282d57600080fd5b612836826127ff565b9392505050565b803560ff8116811461281657600080fd5b60006020828403121561286057600080fd5b6128368261283d565b6000806040838503121561287c57600080fd5b50508035926020909101359150565b60006020828403121561289d57600080fd5b5035919050565b6020808252825182820181905260009190848201906040850190845b818110156128dc578351835292840192918401916001016128c0565b50909695505050505050565b80356001600160c01b038116811461281657600080fd5b60008060006060848603121561291457600080fd5b61291d846128e8565b925061292b602085016127ff565b91506129396040850161283d565b90509250925092565b634e487b7160e01b600052604160045260246000fd5b608081018181106001600160401b038211171561297757612977612942565b60405250565b601f8201601f191681016001600160401b03811182821017156129a2576129a2612942565b6040525050565b803563ffffffff8116811461281657600080fd5b80356001600160a01b038116811461281657600080fd5b600060208083850312156129e757600080fd5b82356001600160401b03808211156129fe57600080fd5b818501915085601f830112612a1257600080fd5b813581811115612a2457612a24612942565b60409150604051612a3a858360051b018261297d565b81815260079190911b830184019084810188831115612a5857600080fd5b938501935b82851015612abc576080858a031215612a765760008081fd5b8351612a8181612958565b612a8a866129a9565b81528686013587820152612a9f8587016129bd565b818601526060868101359082015281526080909401938501612a5d565b50979650505050505050565b60008060408385031215612adb57600080fd5b82359150612aeb602084016129a9565b90509250929050565b60008060408385031215612b0757600080fd5b823591506020830135612b1981612738565b809150509250929050565b600060208284031215612b3657600080fd5b612836826128e8565b600060208284031215612b5157600080fd5b612836826129bd565b634e487b7160e01b600052601160045260246000fd5b81810381811115611b4857611b48612b5a565b80820180821115611b4857611b48612b5a565b634e487b7160e01b600052603260045260246000fd5b600060018201612bbe57612bbe612b5a565b5060010190565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b634e487b7160e01b600052601260045260246000fd5b600082612c1f57612c1f612bfa565b500690565b600081612c3357612c33612b5a565b506000190190565b6020808252602e908201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160408201526d191e481a5b9a5d1a585b1a5e995960921b606082015260800190565b6001600160801b03818116838216028082169190828114612cac57612cac612b5a565b505092915050565b60006001600160801b0380841680612cce57612cce612bfa565b92169190910492915050565b6001600160801b03818116838216019080821115612cfa57612cfa612b5a565b5092915050565b8082028115828204841417611b4857611b48612b5a565b600060208284031215612d2a57600080fd5b5051919050565b600060033d1115612d4a5760046000803e5060005160e01c5b90565b600060443d1015612d5b5790565b6040516003193d81016004833e81513d6001600160401b038160248401118184111715612d8a57505050505090565b8285019150815181811115612da25750505050505090565b843d8701016020828501011115612dbc5750505050505090565b612dcb6020828601018761297d565b509095945050505050565b64ffffffffff818116838216019080821115612cfa57612cfa612b5a565b600082612e0357612e03612bfa565b500490565b600060208284031215612e1a57600080fd5b81516128368161273856fea26469706673582212204eed286559142f12f42055a0eba0e732348e19053404b823817c2b809c389e7864736f6c63430008170033000000000000000000000000054183db3be7e1ae513dbb0f26288084a2337531000000000000000000000000fff9976782d46cc05630d1f6ebab18b2324d6b140000000000000000000000000000000000000000000000000000000000000078", + "nonce": "0x13e", + "chainId": "0xaa36a7", + "accessList": null, + "type": null + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0xaa2b6df4f1a79de290644e6bb008d8c3b633a8f32a100da658fb3c2374afff40", + "transactionType": "CREATE", + "contractName": "NounsAuctionHousePreV2Migration", + "contractAddress": "0x5939286012f3ea301e0a904be1a3ad72c4292fec", + "function": null, + "arguments": null, + "transaction": { + "from": "0xad36c32f3c28a9214adcf50a09998de1d3b0ee06", + "to": null, + "gas": "0x92cc9", + "value": "0x0", + "input": "0x608060405234801561001057600080fd5b50610769806100206000396000f3fe608060405234801561001057600080fd5b50600436106100575760003560e01c80635c975abb1461005c578063715018a6146100775780638da5cb5b146100815780638fd3ab801461009c578063f2fde38b146100a4575b600080fd5b60335460ff1660405190151581526020015b60405180910390f35b61007f6100b7565b005b6097546040516001600160a01b03909116815260200161006e565b61007f6100f6565b61007f6100b23660046106ce565b6105e1565b6097546001600160a01b031633146100ea5760405162461bcd60e51b81526004016100e1906106fe565b60405180910390fd5b6100f4600061067c565b565b6097546001600160a01b031633146101205760405162461bcd60e51b81526004016100e1906106fe565b600060c99050600060c990506000826040518060e00160405290816000820160009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b031681526020016001820160009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b0316815260200160028201548152602001600382015481526020016004820160009054906101000a900460ff1660ff1660ff16815260200160058201548152602001600682016040518060c0016040529081600082015481526020016001820154815260200160028201548152602001600382015481526020016004820160009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b031681526020016004820160149054906101000a900460ff16151515158152505081525050905060008360000160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060008360010160006101000a8154816001600160a01b0302191690836001600160a01b03160217905550600083600201819055506000836003018190555060008360040160006101000a81548160ff021916908360ff160217905550600083600501819055506040518060c001604052806000815260200160008152602001600081526020016000815260200160006001600160a01b0316815260200160001515815250836006016000820151816000015560208201518160010155604082015181600201556060820151816003015560808201518160040160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060a08201518160040160146101000a81548160ff02191690831515021790555090505080606001518260000160006101000a8154816001600160c01b0302191690836001600160c01b0316021790555080604001518260000160186101000a81548166ffffffffffffff021916908366ffffffffffffff160217905550806080015182600001601f6101000a81548160ff021916908360ff1602179055506040518060e001604052808260c00151600001516001600160601b03168152602001600063ffffffff1681526020018260c00151602001516001600160801b031681526020018260c001516040015164ffffffffff1681526020018260c001516060015164ffffffffff1681526020018260c00151608001516001600160a01b031681526020018260c0015160a0015115158152508260010160008201518160000160006101000a8154816001600160601b0302191690836001600160601b03160217905550602082015181600001600c6101000a81548163ffffffff021916908363ffffffff16021790555060408201518160000160106101000a8154816001600160801b0302191690836001600160801b0316021790555060608201518160010160006101000a81548164ffffffffff021916908364ffffffffff16021790555060808201518160010160056101000a81548164ffffffffff021916908364ffffffffff16021790555060a082015181600101600a6101000a8154816001600160a01b0302191690836001600160a01b0316021790555060c082015181600101601e6101000a81548160ff021916908315150217905550905050505050565b6097546001600160a01b0316331461060b5760405162461bcd60e51b81526004016100e1906106fe565b6001600160a01b0381166106705760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084016100e1565b6106798161067c565b50565b609780546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6000602082840312156106e057600080fd5b81356001600160a01b03811681146106f757600080fd5b9392505050565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260408201526060019056fea2646970667358221220eccf365de37364bac882a745bfa92868d893629bdbb6d40821d4aa7ab61698bd64736f6c63430008170033", + "nonce": "0x13f", + "chainId": "0xaa36a7", + "accessList": null, + "type": null + }, + "additionalContracts": [], + "isFixedGasLimit": false + } + ], + "receipts": [ + { + "status": "0x1", + "cumulativeGasUsed": "0xf8ee17", + "logs": [], + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "type": "0x2", + "transactionHash": "0xdbcdc80fa2440517a1cef2c379a7c181aa3d692b6217c73a848bd39193e38544", + "transactionIndex": "0x6e", + "blockHash": "0x0d5c5288416f7f2b55a71d4a34264ee916bf6d4caad186b8505a02810f8bfa93", + "blockNumber": "0x57e0c1", + "gasUsed": "0x2855e6", + "effectiveGasPrice": "0x2711a", + "from": "0xad36c32f3c28a9214adcf50a09998de1d3b0ee06", + "to": null, + "contractAddress": "0xbb4f08516268be9bc43978edf50ed8a1aceeae26" + }, + { + "status": "0x1", + "cumulativeGasUsed": "0xfffd53", + "logs": [], + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "type": "0x2", + "transactionHash": "0xaa2b6df4f1a79de290644e6bb008d8c3b633a8f32a100da658fb3c2374afff40", + "transactionIndex": "0x6f", + "blockHash": "0x0d5c5288416f7f2b55a71d4a34264ee916bf6d4caad186b8505a02810f8bfa93", + "blockNumber": "0x57e0c1", + "gasUsed": "0x70f3c", + "effectiveGasPrice": "0x2711a", + "from": "0xad36c32f3c28a9214adcf50a09998de1d3b0ee06", + "to": null, + "contractAddress": "0x5939286012f3ea301e0a904be1a3ad72c4292fec" + } + ], + "libraries": [], + "pending": [], + "returns": { + "newLogic": { + "internal_type": "contract NounsAuctionHouseV2", + "value": "0xbb4F08516268Be9BC43978Edf50eD8A1ACEEae26" + }, + "migratorLogic": { + "internal_type": "contract NounsAuctionHousePreV2Migration", + "value": "0x5939286012F3eA301E0a904BE1A3aD72C4292FeC" + } + }, + "timestamp": 1713863057, + "chain": 11155111, + "commit": "82b8d911" +} \ No newline at end of file diff --git a/packages/nouns-contracts/broadcast/DeployAuctionHouseV2Sepolia.s.sol/11155111/run-latest.json b/packages/nouns-contracts/broadcast/DeployAuctionHouseV2Sepolia.s.sol/11155111/run-latest.json new file mode 100644 index 0000000000..7ceabe9f73 --- /dev/null +++ b/packages/nouns-contracts/broadcast/DeployAuctionHouseV2Sepolia.s.sol/11155111/run-latest.json @@ -0,0 +1,99 @@ +{ + "transactions": [ + { + "hash": "0xdbcdc80fa2440517a1cef2c379a7c181aa3d692b6217c73a848bd39193e38544", + "transactionType": "CREATE", + "contractName": "NounsAuctionHouseV2", + "contractAddress": "0xbb4f08516268be9bc43978edf50ed8a1aceeae26", + "function": null, + "arguments": [ + "0x054183Db3bE7E1AE513DBb0F26288084a2337531", + "0xfFf9976782d46CC05630D1f6eBAb18b2324d6B14", + "120" + ], + "transaction": { + "from": "0xad36c32f3c28a9214adcf50a09998de1d3b0ee06", + "to": null, + "gas": "0x346bb7", + "value": "0x0", + "input": "0x60e06040523480156200001157600080fd5b506040516200302438038062003024833981016040819052620000349162000127565b600054610100900460ff16806200004e575060005460ff16155b620000b65760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b606482015260840160405180910390fd5b600054610100900460ff16158015620000d9576000805461ffff19166101011790555b6001600160a01b03808516608052831660a05260c0829052801562000104576000805461ff00191690555b505050506200016f565b6001600160a01b03811681146200012457600080fd5b50565b6000806000606084860312156200013d57600080fd5b83516200014a816200010e565b60208501519093506200015d816200010e565b80925050604084015190509250925092565b60805160a05160c051612e5b620001c96000396000818161023c0152611ca40152600081816102ff0152818161243e01526124d301526000818161027e01528181611be30152818161217201526122170152612e5b6000f3fe6080604052600436106101cd5760003560e01c80638da5cb5b116100f7578063af64dd3011610095578063db2e1eed11610064578063db2e1eed14610768578063ec91f2a4146107a0578063f25efffc146107c7578063f2fde38b146107dc57600080fd5b8063af64dd30146106d5578063b1296a94146106f5578063b296024d14610715578063c0555d981461074857600080fd5b80639903cce6116100d15780639903cce61461066d578063a4d0a17e1461068d578063a94dd8a0146106a2578063abbfb786146106c257600080fd5b80638da5cb5b1461054b5780639149295614610569578063945c37cb1461059657600080fd5b80635112fabf1161016f578063715018a61161013e578063715018a6146103c25780637d9f6db5146103d75780638456cb591461050757806385317a291461051c57600080fd5b80635112fabf146103215780635c975abb14610341578063659dd2b4146103645780636dd83b5d1461037757600080fd5b80632de45f18116101ab5780632de45f181461026c57806336ebdb38146102b85780633f4ba83a146102d85780633fc8cef3146102ed57600080fd5b806309b85709146101d25780630ba4e9ea146102085780630fb5a6b41461022a575b600080fd5b3480156101de57600080fd5b506101f26101ed366004612746565b6107fc565b6040516101ff919061277f565b60405180910390f35b34801561021457600080fd5b5061022861022336600461281b565b610a4f565b005b34801561023657600080fd5b5061025e7f000000000000000000000000000000000000000000000000000000000000000081565b6040519081526020016101ff565b34801561027857600080fd5b506102a07f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020016101ff565b3480156102c457600080fd5b506102286102d336600461284e565b610b2d565b3480156102e457600080fd5b50610228610bfa565b3480156102f957600080fd5b506102a07f000000000000000000000000000000000000000000000000000000000000000081565b34801561032d57600080fd5b5061022861033c366004612869565b610c5a565b34801561034d57600080fd5b5060335460ff1660405190151581526020016101ff565b61022861037236600461288b565b610cd6565b34801561038357600080fd5b506103ad61039236600461288b565b600090815260cc602052604090206001015463ffffffff1690565b60405163ffffffff90911681526020016101ff565b3480156103ce57600080fd5b50610228610ce4565b3480156103e357600080fd5b506104946040805160c081018252600080825260208201819052918101829052606081018290526080810182905260a0810191909152506040805160c08101825260ca546001600160601b0381168252600160801b90046001600160801b0316602082015260cb5464ffffffffff80821693830193909352600160281b81049092166060820152600160501b82046001600160a01b03166080820152600160f01b90910460ff16151560a082015290565b6040516101ff919081516001600160601b031681526020808301516001600160801b03169082015260408083015164ffffffffff90811691830191909152606080840151909116908201526080808301516001600160a01b03169082015260a09182015115159181019190915260c00190565b34801561051357600080fd5b50610228610d18565b34801561052857600080fd5b506105336201518081565b60405166ffffffffffffff90911681526020016101ff565b34801561055757600080fd5b506097546001600160a01b03166102a0565b34801561057557600080fd5b5061058961058436600461288b565b610d4a565b6040516101ff91906128a4565b3480156105a257600080fd5b5060ca5460cb5461060a916001600160601b03811691600160601b820463ffffffff1691600160801b90046001600160801b03169064ffffffffff80821691600160281b810490911690600160501b81046001600160a01b031690600160f01b900460ff1687565b604080516001600160601b03909816885263ffffffff90961660208801526001600160801b039094169486019490945264ffffffffff91821660608601521660808401526001600160a01b0390911660a0830152151560c082015260e0016101ff565b34801561067957600080fd5b506102286106883660046128ff565b610f61565b34801561069957600080fd5b50610228611032565b3480156106ae57600080fd5b506102286106bd3660046129d4565b611083565b6102286106d0366004612ac8565b6111c0565b3480156106e157600080fd5b506101f26106f0366004612af4565b611602565b34801561070157600080fd5b506101f2610710366004612746565b61180b565b34801561072157600080fd5b5060c95461073690600160f81b900460ff1681565b60405160ff90911681526020016101ff565b34801561075457600080fd5b50610228610763366004612b24565b6119c9565b34801561077457600080fd5b5060c954610788906001600160c01b031681565b6040516001600160c01b0390911681526020016101ff565b3480156107ac57600080fd5b5060c95461053390600160c01b900466ffffffffffffff1681565b3480156107d357600080fd5b50610228611a41565b3480156107e857600080fd5b506102286107f7366004612b3f565b611a97565b60ca546060906001600160601b0316808511156108545760405162461bcd60e51b81526020600482015260116024820152707374617274496420746f6f206c6172676560781b60448201526064015b60405180910390fd5b61085e8582612b70565b610869906001612b83565b6001600160401b0381111561088057610880612942565b6040519080825280602002602001820160405280156108d957816020015b6040805160a08101825260008082526020808301829052928201819052606082018190526080820152825260001990920191018161089e5790505b50915060006108e661270a565b865b838111610a3757600081815260cc6020908152604091829020825160a081018452815463ffffffff8082168352600160201b8083046001600160401b031695840195909552600160601b9091046001600160a01b0316948201949094526001909101549283166060820152910460ff1615156080820152915085801561097957506001826000015163ffffffff1611155b610a2757838114801561099757506001826000015163ffffffff1611155b610a2757815163ffffffff168710610a37576040518060a00160405280836000015163ffffffff1681526020016109d18460200151611b2f565b815260200183604001516001600160a01b03168152602001828152602001836060015163ffffffff16815250858481518110610a0f57610a0f612b96565b602002602001018190525082610a2490612bac565b92505b610a3081612bac565b90506108e8565b508184511115610a45578184525b5050509392505050565b6097546001600160a01b03163314610a795760405162461bcd60e51b815260040161084b90612bc5565b6201518066ffffffffffffff82161115610acc5760405162461bcd60e51b815260206004820152601460248201527374696d6542756666657220746f6f206c6172676560601b604482015260640161084b565b60c9805466ffffffffffffff60c01b1916600160c01b66ffffffffffffff8416908102919091179091556040519081527f1b55d9f7002bda4490f467e326f22a4a847629c0f2d1ed421607d318d25b410d906020015b60405180910390a150565b6097546001600160a01b03163314610b575760405162461bcd60e51b815260040161084b90612bc5565b60008160ff1611610baa5760405162461bcd60e51b815260206004820152601960248201527f6d7573742062652067726561746572207468616e207a65726f00000000000000604482015260640161084b565b60c980546001600160f81b0316600160f81b60ff8416908102919091179091556040519081527fec5ccd96cc77b6219e9d44143df916af68fc169339ea7de5008ff15eae13450d90602001610b22565b6097546001600160a01b03163314610c245760405162461bcd60e51b815260040161084b90612bc5565b610c2c611b4e565b60cb5464ffffffffff161580610c4b575060cb54600160f01b900460ff165b15610c5857610c58611be1565b565b815b81811015610cd15761071c8111158015610c7e5750610c7c600a82612c10565b155b610cc957600081815260cc602052604081208054909163ffffffff9091169003610cc757805463ffffffff1916600190811782558101805464ff000000001916600160201b1790555b505b600101610c5c565b505050565b610ce18160006111c0565b50565b6097546001600160a01b03163314610d0e5760405162461bcd60e51b815260040161084b90612bc5565b610c586000611da0565b6097546001600160a01b03163314610d425760405162461bcd60e51b815260040161084b90612bc5565b610c58611df2565b60ca5460cb546060916001600160601b031690600160f01b900460ff16158015610d745750600081115b15610d8757610d84600182612b70565b90505b826001600160401b03811115610d9f57610d9f612942565b604051908082528060200260200182016040528015610dc8578160200160208202803683370190505b5091506000610dd561270a565b825b600081118015610de657508583105b15610f145761071c8111158015610e055750610e03600a82612c10565b155b610f0457600081815260cc6020908152604091829020825160a081018452815463ffffffff808216808452600160201b8084046001600160401b031696850196909652600160601b9092046001600160a01b03169583019590955260019283015494851660608301529290930460ff161515608084015291935011610ebb5760405162461bcd60e51b815260206004820152600c60248201526b4d697373696e67206461746160a01b604482015260640161084b565b60408201516001600160a01b031615610f0457610edb8260200151611b2f565b858481518110610eed57610eed612b96565b6020908102919091010152610f0183612bac565b92505b610f0d81612c24565b9050610dd7565b50818514610f595760405162461bcd60e51b81526020600482015260126024820152714e6f7420656e6f75676820686973746f727960701b604482015260640161084b565b505050919050565b600054610100900460ff1680610f7a575060005460ff16155b610f965760405162461bcd60e51b815260040161084b90612c3b565b600054610100900460ff16158015610fb8576000805461ffff19166101011790555b610fc0611e6d565b610fc8611ee8565b610fd0611f47565b610fd8611df2565b60c980546001600160c01b0386166001600160f81b031990911617600160c01b66ffffffffffffff861602176001600160f81b0316600160f81b60ff851602179055801561102c576000805461ff00191690555b50505050565b60335460ff1661107b5760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b604482015260640161084b565b610c58611fae565b6097546001600160a01b031633146110ad5760405162461bcd60e51b815260040161084b90612bc5565b60005b81518110156111bc57600060cc60008484815181106110d1576110d1612b96565b602002602001015160600151815260200190815260200160002090508282815181106110ff576110ff612b96565b602090810291909101015151815463ffffffff191663ffffffff90911617815582516111489084908490811061113757611137612b96565b60200260200101516020015161241e565b81546001600160401b0391909116600160201b026bffffffffffffffff0000000019909116178155825183908390811061118457611184612b96565b60209081029190910101516040015181546001600160a01b03909116600160601b026001600160601b039091161790556001016110b0565b5050565b6040805160e08101825260ca546001600160601b038116808352600160601b820463ffffffff166020840152600160801b9091046001600160801b03169282019290925260cb5464ffffffffff8082166060840152600160281b8204166080830152600160501b81046001600160a01b031660a0830152600160f01b900460ff908116151560c083015260c95491926001600160c01b03831692600160c01b810466ffffffffffffff1692600160f81b909104169086146112c35760405162461bcd60e51b815260206004820152601760248201527f4e6f756e206e6f7420757020666f722061756374696f6e000000000000000000604482015260640161084b565b836080015164ffffffffff16421061130f5760405162461bcd60e51b815260206004820152600f60248201526e105d58dd1a5bdb88195e1c1a5c9959608a1b604482015260640161084b565b826001600160c01b03163410156113685760405162461bcd60e51b815260206004820152601f60248201527f4d7573742073656e64206174206c656173742072657365727665507269636500604482015260640161084b565b60648160ff16856040015161137d9190612c89565b6113879190612cb4565b84604001516113969190612cda565b6001600160801b0316341015611416576040805162461bcd60e51b81526020600482015260248101919091527f4d7573742073656e64206d6f7265207468616e206c617374206269642062792060448201527f6d696e426964496e6372656d656e7450657263656e7461676520616d6f756e74606482015260840161084b565b60ca80546001600160601b0316600160601b63ffffffff8816026001600160801b0390811691909117600160801b349092169190910217905560cb80547fffff0000000000000000000000000000000000000000ffffffffffffffffffff1633600160501b02179055608084015160009066ffffffffffffff8416906114a490429064ffffffffff16612b70565b865160408051338152346020820152939092109183018290529092506001600160601b0316907f1159164c56f277e6fc99c11731bd380e0347deb969b75523398734c252706ea39060600160405180910390a263ffffffff86161561154b57845160405134815263ffffffff8816916001600160601b0316907f38e150a71033b4c9a3eeb9ebe568476f075a558e47171f3b5d715aa0cf6cd1b59060200160405180910390a35b80156115cd5761156466ffffffffffffff841642612b83565b64ffffffffff166080860181905260cb805469ffffffffff00000000001916600160281b830217905585516040519182526001600160601b0316907f6e912a3a9105bdd2af817ba5adc14e6c127c1035b5b648faa29ca0d58ab8ff4e9060200160405180910390a25b60a08501516001600160a01b038116156115f8576115f88187604001516001600160801b031661242e565b5050505050505050565b60ca5460cb546060916001600160601b031690600160f01b900460ff1615801561162c5750600081115b1561163f5761163c600182612b70565b90505b836001600160401b0381111561165757611657612942565b6040519080825280602002602001820160405280156116b057816020015b6040805160a0810182526000808252602080830182905292820181905260608201819052608082015282526000199092019101816116755790505b50915060006116bd61270a565b825b868310156117f557600081815260cc6020908152604091829020825160a081018452815463ffffffff8082168352600160201b8083046001600160401b031695840195909552600160601b9091046001600160a01b0316948201949094526001909101549283166060820152910460ff1615156080820152915085801561175157506001826000015163ffffffff1611155b156117615780156117f5576117e5565b6040518060a00160405280836000015163ffffffff1681526020016117898460200151611b2f565b815260200183604001516001600160a01b03168152602001828152602001836060015163ffffffff168152508584815181106117c7576117c7612b96565b6020026020010181905250826117dc90612bac565b925080156117f5575b6117ee81612c24565b90506116bf565b5081861115611802578184525b50505092915050565b60606118178484612b70565b6001600160401b0381111561182e5761182e612942565b60405190808252806020026020018201604052801561188757816020015b6040805160a08101825260008082526020808301829052928201819052606082018190526080820152825260001990920191018161184c5790505b509050600061189461270a565b855b858110156119b257600081815260cc6020908152604091829020825160a081018452815463ffffffff8082168352600160201b8083046001600160401b031695840195909552600160601b9091046001600160a01b0316948201949094526001909101549283166060820152910460ff1615156080820152915084801561192857506001826000015163ffffffff1611155b6119aa576040518060a00160405280836000015163ffffffff1681526020016119548460200151611b2f565b815260200183604001516001600160a01b03168152602001828152602001836060015163ffffffff1681525084848151811061199257611992612b96565b6020026020010181905250826119a790612bac565b92505b600101611896565b5081835111156119c0578183525b50509392505050565b6097546001600160a01b031633146119f35760405162461bcd60e51b815260040161084b90612bc5565b60c980546001600160c01b0319166001600160c01b0383169081179091556040519081527f6ab2e127d7fdf53b8f304e59d3aab5bfe97979f52a85479691a6fab27a28a6b290602001610b22565b60335460ff1615611a875760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b604482015260640161084b565b611a8f611fae565b610c58611be1565b6097546001600160a01b03163314611ac15760405162461bcd60e51b815260040161084b90612bc5565b6001600160a01b038116611b265760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b606482015260840161084b565b610ce181611da0565b6000611b486001600160401b0383166305f5e100612d01565b92915050565b60335460ff16611b975760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b604482015260640161084b565b6033805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316631249c58b6040518163ffffffff1660e01b81526004016020604051808303816000875af1925050508015611c5d575060408051601f3d908101601f19168201909252611c5a91810190612d18565b60015b611c9c57611c69612d31565b806308c379a003611c905750611c7d612d4d565b80611c885750611c92565b610ce1611df2565b505b3d6000803e3d6000fd5b426000611cc97f000000000000000000000000000000000000000000000000000000000000000083612dd6565b6040805160e0810182526001600160601b0386168082526000602080840182905283850182905264ffffffffff888116606086018190529087166080860181905260a0860184905260c09095019290925260ca9290925560cb805469ffffffffffffffffffff19168217600160281b8502177fff000000000000000000000000000000000000000000ffffffffffffffffffff16905583519081529081019190915291925084917fd6eddd1118d71820909c1197aa966dbc15ed6f508554252169cc3d5ccac756ca910160405180910390a2505050565b609780546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b60335460ff1615611e385760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b604482015260640161084b565b6033805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258611bc43390565b600054610100900460ff1680611e86575060005460ff16155b611ea25760405162461bcd60e51b815260040161084b90612c3b565b600054610100900460ff16158015611ec4576000805461ffff19166101011790555b611ecc612544565b611ed46125ae565b8015610ce1576000805461ff001916905550565b600054610100900460ff1680611f01575060005460ff16155b611f1d5760405162461bcd60e51b815260040161084b90612c3b565b600054610100900460ff16158015611f3f576000805461ffff19166101011790555b611ed4612623565b600054610100900460ff1680611f60575060005460ff16155b611f7c5760405162461bcd60e51b815260040161084b90612c3b565b600054610100900460ff16158015611f9e576000805461ffff19166101011790555b611fa6612544565b611ed4612693565b6040805160e08101825260ca546001600160601b0381168252600160601b810463ffffffff166020830152600160801b90046001600160801b03169181019190915260cb5464ffffffffff80821660608401819052600160281b83049091166080840152600160501b82046001600160a01b031660a0840152600160f01b90910460ff16151560c083015260000361207f5760405162461bcd60e51b815260206004820152601460248201527320bab1ba34b7b7103430b9b713ba103132b3bab760611b604482015260640161084b565b8060c00151156120d15760405162461bcd60e51b815260206004820181905260248201527f41756374696f6e2068617320616c7265616479206265656e20736574746c6564604482015260640161084b565b806080015164ffffffffff1642101561212c5760405162461bcd60e51b815260206004820152601860248201527f41756374696f6e206861736e277420636f6d706c657465640000000000000000604482015260640161084b565b60cb805460ff60f01b1916600160f01b17905560a08101516001600160a01b03166121db578051604051630852cd8d60e31b81526001600160601b0390911660048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906342966c6890602401600060405180830381600087803b1580156121be57600080fd5b505af11580156121d2573d6000803e3d6000fd5b50505050612276565b60a081015181516040516323b872dd60e01b81523060048201526001600160a01b0392831660248201526001600160601b0390911660448201527f0000000000000000000000000000000000000000000000000000000000000000909116906323b872dd90606401600060405180830381600087803b15801561225d57600080fd5b505af1158015612271573d6000803e3d6000fd5b505050505b60408101516001600160801b0316156122b1576122b161229e6097546001600160a01b031690565b82604001516001600160801b031661242e565b80516001600160601b0316600090815260cc602052604090819020805463ffffffff19164263ffffffff16178155908201516122f5906001600160801b031661241e565b815460a08401516001600160a01b0316600160601b026001600160601b036001600160401b0393909316600160201b029290921663ffffffff918216179190911782556020830151161561236457602082015160018201805463ffffffff191663ffffffff9092169190911790555b815160a083015160408085015181516001600160a01b0390931683526001600160801b031660208301526001600160601b03909216917fc9f72b276a388619c6d185d146697036241880c36654b1a3ffdad07c24038d99910160405180910390a2602082015163ffffffff16156111bc57816020015163ffffffff1682600001516001600160601b03167ff445afb110f5e782fc78bf23e7066d3c5a95f7b57bd25fb718a29ad0287db2b960405160405180910390a35050565b6000611b486305f5e10083612df4565b61243882826126f3565b6111bc577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b15801561249757600080fd5b505af11580156124ab573d6000803e3d6000fd5b505060405163a9059cbb60e01b81526001600160a01b038681166004830152602482018690527f000000000000000000000000000000000000000000000000000000000000000016935063a9059cbb925060440190506020604051808303816000875af1158015612520573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cd19190612e08565b600054610100900460ff168061255d575060005460ff16155b6125795760405162461bcd60e51b815260040161084b90612c3b565b600054610100900460ff16158015611ed4576000805461ffff19166101011790558015610ce1576000805461ff001916905550565b600054610100900460ff16806125c7575060005460ff16155b6125e35760405162461bcd60e51b815260040161084b90612c3b565b600054610100900460ff16158015612605576000805461ffff19166101011790555b6033805460ff191690558015610ce1576000805461ff001916905550565b600054610100900460ff168061263c575060005460ff16155b6126585760405162461bcd60e51b815260040161084b90612c3b565b600054610100900460ff1615801561267a576000805461ffff19166101011790555b60016065558015610ce1576000805461ff001916905550565b600054610100900460ff16806126ac575060005460ff16155b6126c85760405162461bcd60e51b815260040161084b90612c3b565b600054610100900460ff161580156126ea576000805461ffff19166101011790555b611ed433611da0565b6000806000806000808688617530f1949350505050565b6040805160a08101825260008082526020820181905291810182905260608101829052608081019190915290565b8015158114610ce157600080fd5b60008060006060848603121561275b57600080fd5b8335925060208401359150604084013561277481612738565b809150509250925092565b602080825282518282018190526000919060409081850190868401855b828110156127f2578151805163ffffffff90811686528782015188870152868201516001600160a01b03168787015260608083015190870152608091820151169085015260a0909301929085019060010161279c565b5091979650505050505050565b803566ffffffffffffff8116811461281657600080fd5b919050565b60006020828403121561282d57600080fd5b612836826127ff565b9392505050565b803560ff8116811461281657600080fd5b60006020828403121561286057600080fd5b6128368261283d565b6000806040838503121561287c57600080fd5b50508035926020909101359150565b60006020828403121561289d57600080fd5b5035919050565b6020808252825182820181905260009190848201906040850190845b818110156128dc578351835292840192918401916001016128c0565b50909695505050505050565b80356001600160c01b038116811461281657600080fd5b60008060006060848603121561291457600080fd5b61291d846128e8565b925061292b602085016127ff565b91506129396040850161283d565b90509250925092565b634e487b7160e01b600052604160045260246000fd5b608081018181106001600160401b038211171561297757612977612942565b60405250565b601f8201601f191681016001600160401b03811182821017156129a2576129a2612942565b6040525050565b803563ffffffff8116811461281657600080fd5b80356001600160a01b038116811461281657600080fd5b600060208083850312156129e757600080fd5b82356001600160401b03808211156129fe57600080fd5b818501915085601f830112612a1257600080fd5b813581811115612a2457612a24612942565b60409150604051612a3a858360051b018261297d565b81815260079190911b830184019084810188831115612a5857600080fd5b938501935b82851015612abc576080858a031215612a765760008081fd5b8351612a8181612958565b612a8a866129a9565b81528686013587820152612a9f8587016129bd565b818601526060868101359082015281526080909401938501612a5d565b50979650505050505050565b60008060408385031215612adb57600080fd5b82359150612aeb602084016129a9565b90509250929050565b60008060408385031215612b0757600080fd5b823591506020830135612b1981612738565b809150509250929050565b600060208284031215612b3657600080fd5b612836826128e8565b600060208284031215612b5157600080fd5b612836826129bd565b634e487b7160e01b600052601160045260246000fd5b81810381811115611b4857611b48612b5a565b80820180821115611b4857611b48612b5a565b634e487b7160e01b600052603260045260246000fd5b600060018201612bbe57612bbe612b5a565b5060010190565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b634e487b7160e01b600052601260045260246000fd5b600082612c1f57612c1f612bfa565b500690565b600081612c3357612c33612b5a565b506000190190565b6020808252602e908201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160408201526d191e481a5b9a5d1a585b1a5e995960921b606082015260800190565b6001600160801b03818116838216028082169190828114612cac57612cac612b5a565b505092915050565b60006001600160801b0380841680612cce57612cce612bfa565b92169190910492915050565b6001600160801b03818116838216019080821115612cfa57612cfa612b5a565b5092915050565b8082028115828204841417611b4857611b48612b5a565b600060208284031215612d2a57600080fd5b5051919050565b600060033d1115612d4a5760046000803e5060005160e01c5b90565b600060443d1015612d5b5790565b6040516003193d81016004833e81513d6001600160401b038160248401118184111715612d8a57505050505090565b8285019150815181811115612da25750505050505090565b843d8701016020828501011115612dbc5750505050505090565b612dcb6020828601018761297d565b509095945050505050565b64ffffffffff818116838216019080821115612cfa57612cfa612b5a565b600082612e0357612e03612bfa565b500490565b600060208284031215612e1a57600080fd5b81516128368161273856fea26469706673582212204eed286559142f12f42055a0eba0e732348e19053404b823817c2b809c389e7864736f6c63430008170033000000000000000000000000054183db3be7e1ae513dbb0f26288084a2337531000000000000000000000000fff9976782d46cc05630d1f6ebab18b2324d6b140000000000000000000000000000000000000000000000000000000000000078", + "nonce": "0x13e", + "chainId": "0xaa36a7", + "accessList": null, + "type": null + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0xaa2b6df4f1a79de290644e6bb008d8c3b633a8f32a100da658fb3c2374afff40", + "transactionType": "CREATE", + "contractName": "NounsAuctionHousePreV2Migration", + "contractAddress": "0x5939286012f3ea301e0a904be1a3ad72c4292fec", + "function": null, + "arguments": null, + "transaction": { + "from": "0xad36c32f3c28a9214adcf50a09998de1d3b0ee06", + "to": null, + "gas": "0x92cc9", + "value": "0x0", + "input": "0x608060405234801561001057600080fd5b50610769806100206000396000f3fe608060405234801561001057600080fd5b50600436106100575760003560e01c80635c975abb1461005c578063715018a6146100775780638da5cb5b146100815780638fd3ab801461009c578063f2fde38b146100a4575b600080fd5b60335460ff1660405190151581526020015b60405180910390f35b61007f6100b7565b005b6097546040516001600160a01b03909116815260200161006e565b61007f6100f6565b61007f6100b23660046106ce565b6105e1565b6097546001600160a01b031633146100ea5760405162461bcd60e51b81526004016100e1906106fe565b60405180910390fd5b6100f4600061067c565b565b6097546001600160a01b031633146101205760405162461bcd60e51b81526004016100e1906106fe565b600060c99050600060c990506000826040518060e00160405290816000820160009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b031681526020016001820160009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b0316815260200160028201548152602001600382015481526020016004820160009054906101000a900460ff1660ff1660ff16815260200160058201548152602001600682016040518060c0016040529081600082015481526020016001820154815260200160028201548152602001600382015481526020016004820160009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b031681526020016004820160149054906101000a900460ff16151515158152505081525050905060008360000160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060008360010160006101000a8154816001600160a01b0302191690836001600160a01b03160217905550600083600201819055506000836003018190555060008360040160006101000a81548160ff021916908360ff160217905550600083600501819055506040518060c001604052806000815260200160008152602001600081526020016000815260200160006001600160a01b0316815260200160001515815250836006016000820151816000015560208201518160010155604082015181600201556060820151816003015560808201518160040160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060a08201518160040160146101000a81548160ff02191690831515021790555090505080606001518260000160006101000a8154816001600160c01b0302191690836001600160c01b0316021790555080604001518260000160186101000a81548166ffffffffffffff021916908366ffffffffffffff160217905550806080015182600001601f6101000a81548160ff021916908360ff1602179055506040518060e001604052808260c00151600001516001600160601b03168152602001600063ffffffff1681526020018260c00151602001516001600160801b031681526020018260c001516040015164ffffffffff1681526020018260c001516060015164ffffffffff1681526020018260c00151608001516001600160a01b031681526020018260c0015160a0015115158152508260010160008201518160000160006101000a8154816001600160601b0302191690836001600160601b03160217905550602082015181600001600c6101000a81548163ffffffff021916908363ffffffff16021790555060408201518160000160106101000a8154816001600160801b0302191690836001600160801b0316021790555060608201518160010160006101000a81548164ffffffffff021916908364ffffffffff16021790555060808201518160010160056101000a81548164ffffffffff021916908364ffffffffff16021790555060a082015181600101600a6101000a8154816001600160a01b0302191690836001600160a01b0316021790555060c082015181600101601e6101000a81548160ff021916908315150217905550905050505050565b6097546001600160a01b0316331461060b5760405162461bcd60e51b81526004016100e1906106fe565b6001600160a01b0381166106705760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084016100e1565b6106798161067c565b50565b609780546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6000602082840312156106e057600080fd5b81356001600160a01b03811681146106f757600080fd5b9392505050565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260408201526060019056fea2646970667358221220eccf365de37364bac882a745bfa92868d893629bdbb6d40821d4aa7ab61698bd64736f6c63430008170033", + "nonce": "0x13f", + "chainId": "0xaa36a7", + "accessList": null, + "type": null + }, + "additionalContracts": [], + "isFixedGasLimit": false + } + ], + "receipts": [ + { + "status": "0x1", + "cumulativeGasUsed": "0xf8ee17", + "logs": [], + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "type": "0x2", + "transactionHash": "0xdbcdc80fa2440517a1cef2c379a7c181aa3d692b6217c73a848bd39193e38544", + "transactionIndex": "0x6e", + "blockHash": "0x0d5c5288416f7f2b55a71d4a34264ee916bf6d4caad186b8505a02810f8bfa93", + "blockNumber": "0x57e0c1", + "gasUsed": "0x2855e6", + "effectiveGasPrice": "0x2711a", + "from": "0xad36c32f3c28a9214adcf50a09998de1d3b0ee06", + "to": null, + "contractAddress": "0xbb4f08516268be9bc43978edf50ed8a1aceeae26" + }, + { + "status": "0x1", + "cumulativeGasUsed": "0xfffd53", + "logs": [], + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "type": "0x2", + "transactionHash": "0xaa2b6df4f1a79de290644e6bb008d8c3b633a8f32a100da658fb3c2374afff40", + "transactionIndex": "0x6f", + "blockHash": "0x0d5c5288416f7f2b55a71d4a34264ee916bf6d4caad186b8505a02810f8bfa93", + "blockNumber": "0x57e0c1", + "gasUsed": "0x70f3c", + "effectiveGasPrice": "0x2711a", + "from": "0xad36c32f3c28a9214adcf50a09998de1d3b0ee06", + "to": null, + "contractAddress": "0x5939286012f3ea301e0a904be1a3ad72c4292fec" + } + ], + "libraries": [], + "pending": [], + "returns": { + "newLogic": { + "internal_type": "contract NounsAuctionHouseV2", + "value": "0xbb4F08516268Be9BC43978Edf50eD8A1ACEEae26" + }, + "migratorLogic": { + "internal_type": "contract NounsAuctionHousePreV2Migration", + "value": "0x5939286012F3eA301E0a904BE1A3aD72C4292FeC" + } + }, + "timestamp": 1713863057, + "chain": 11155111, + "commit": "82b8d911" +} \ No newline at end of file diff --git a/packages/nouns-contracts/broadcast/DeployDAOLogicOptimized.s.sol/1/run-1713864921.json b/packages/nouns-contracts/broadcast/DeployDAOLogicOptimized.s.sol/1/run-1713864921.json new file mode 100644 index 0000000000..992fb5ec0a --- /dev/null +++ b/packages/nouns-contracts/broadcast/DeployDAOLogicOptimized.s.sol/1/run-1713864921.json @@ -0,0 +1,245 @@ +{ + "transactions": [ + { + "hash": "0xf5bbdf994c5c451133efb990bcde2544003a5bdd3c924877db95a14b97ab0982", + "transactionType": "CREATE", + "contractName": "NounsDAOAdmin", + "contractAddress": "0xd7c7c3c447df757a77c81fcff07f10bb22d98f4a", + "function": null, + "arguments": null, + "transaction": { + "from": "0x918895f466eb3cd5fb181626f8e1b2fd8a9d5192", + "to": null, + "gas": "0x277cd7", + "value": null, + "input": "0x61230c61003a600b82828239805160001a60731461002d57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600436106102315760003560e01c8063a267a3d11161013a578063db725e17116100c2578063e9c714f211610086578063e9c714f21461052f578063ec91deda14610544578063ee186559146104a2578063f5f4714c14610564578063fd22b60a146104dc57600080fd5b8063db725e17146104d3578063dfcda1ef146104dc578063e2560772146104e6578063e5eb5abf14610506578063e7951bb91461052657600080fd5b8063c10eb14d11610109578063c10eb14d14610478578063c82fbd0814610371578063cbff4a13146104a2578063ccfa51c9146104ab578063d3f662e1146104b357600080fd5b8063a267a3d114610419578063a78b5f1a14610423578063b71d1a0c14610443578063bf7a29631461046357600080fd5b80632df01bdb116101bd57806374b157b81161018c57806374b157b8146103795780637a3da69114610399578063842e4dae146103b95780639547aecb146103d957806397d048e5146103f957600080fd5b80632df01bdb1461031157806344697f981461033157806350196db31461035157806351e313e01461037157600080fd5b80631e7b5d3a116102045780631e7b5d3a146102ad57806326e6dcb0146102c957806327126e67146102d25780632b5ca189146102dc5780632cfc81c6146102fc57600080fd5b806306ef9d36146102365780630dc0ce3f146102585780630ea2d98c1461026d5780631dfb1b5a1461028d575b600080fd5b81801561024257600080fd5b50610256610251366004611ef2565b610584565b005b81801561026457600080fd5b506102566105f2565b81801561027957600080fd5b50610256610288366004611ef2565b610624565b81801561029957600080fd5b506102566102a8366004611ef2565b610715565b6102b66103e881565b6040519081526020015b60405180910390f35b6102b661177081565b6102b66212750081565b8180156102e857600080fd5b506102566102f7366004611f24565b6107f6565b81801561030857600080fd5b50610256610891565b81801561031d57600080fd5b5061025661032c366004611f5d565b610986565b81801561033d57600080fd5b5061025661034c366004611f78565b610a2c565b81801561035d57600080fd5b5061025661036c366004611fcd565b610ad3565b6102b6600181565b81801561038557600080fd5b50610256610394366004611f24565b610c67565b8180156103a557600080fd5b506102566103b4366004611fcd565b610d28565b8180156103c557600080fd5b506102566103d4366004611ef2565b610ecc565b8180156103e557600080fd5b506102566103f4366004612034565b610f82565b81801561040557600080fd5b50610256610414366004611ef2565b610fb8565b6102b66202a30081565b81801561042f57600080fd5b5061025661043e3660046120a7565b6110a6565b81801561044f57600080fd5b5061025661045e366004611f5d565b611129565b81801561046f57600080fd5b506102566111a7565b81801561048457600080fd5b5061048d611262565b604080519283529015156020830152016102c0565b6102b661c4e081565b6102b660c881565b8180156104bf57600080fd5b506102566104ce366004611f5d565b611320565b6102b6611c2081565b6102b6620189c081565b8180156104f257600080fd5b50610256610501366004611f24565b6113b7565b81801561051257600080fd5b50610256610521366004611f24565b611436565b6102b66107d081565b81801561053b57600080fd5b506102566114ef565b81801561055057600080fd5b5061025661055f3660046120e9565b611605565b81801561057057600080fd5b5061025661057f366004611f5d565b6117de565b6000546001600160a01b031633146105af57604051633057182d60e21b815260040160405180910390fd5b7f8008239436e26bac1476fd338f5a2ec6415794efc1afa04145a4845547f37adc60006017015460408051918252602082018490520160405180910390a1601755565b6000546001600160a01b0316331461061d57604051633057182d60e21b815260040160405180910390fd5b6000601955565b6000546001600160a01b0316331461064f57604051633057182d60e21b815260040160405180910390fd5b611c2081101580156106645750620189c08111155b6106cf5760405162461bcd60e51b815260206004820152603160248201527f4e6f756e7344414f3a3a5f736574566f74696e67506572696f643a20696e76616044820152701b1a59081d9bdd1a5b99c81c195c9a5bd9607a1b60648201526084015b60405180910390fd5b600580549082905560408051828152602081018490527f7e3f7f0708a84de9203036abaa450dccc85ad5ff52f78c170f3edb55cf5e882891015b60405180910390a15050565b6000546001600160a01b0316331461074057604051633057182d60e21b815260040160405180910390fd5b600181101580156107545750620189c08111155b6107b85760405162461bcd60e51b815260206004820152602f60248201527f4e6f756e7344414f3a3a5f736574566f74696e6744656c61793a20696e76616c60448201526e696420766f74696e672064656c617960881b60648201526084016106c6565b600480549082905560408051828152602081018490527fc565b045403dc03c2eea82b81a0465edad9e2e7fc4d97e11421c209da93d7a939101610709565b6000546001600160a01b0316331461082157604051633057182d60e21b815260040160405180910390fd5b600061082f43825b9061185c565b60408101805163ffffffff851690915290915061084b82611b73565b6040805163ffffffff8084168252851660208201527f5e3adb1066359dafa23c629f245d93543856115700821dcb4debc416f393c46991015b60405180910390a1505050565b6000600e01546001600160a01b031633146108bf57604051631bd9bb1b60e31b815260040160405180910390fd5b600354600e546040517fc5644f3588a066b15dcf6b636b74aadca57cfaccf608d9de7d8786364b7a8d0292610902926001600160a01b0391821692911690612123565b60405180910390a1600e546001600160a01b031660005b60030180546001600160a01b0319166001600160a01b03928316179055600e546040517f7ad92e57a52c4e3e83ba624622b14e3a5efa0160dd6f9a7975c43ea66bad79ea9261096c921690600090612123565b60405180910390a1600e80546001600160a01b0319169055565b6000546001600160a01b031633146109b157604051633057182d60e21b815260040160405180910390fd5b7ff890a07a97cb2de686a62235272191a50a2113c4fda17ce6ab5ffd20a06d56d36000601001546040516109f791600160601b90046001600160a01b0316908490612123565b60405180910390a1601080546001600160a01b03909216600160601b026bffffffffffffffffffffffff909216919091179055565b6000546001600160a01b03163314610a5757604051633057182d60e21b815260040160405180910390fd5b600980546001600160a01b038086166001600160a01b0319928316811790935560188054868316908416811790915560008054928616929093168217909255604080519384526020840192909252908201527f13c01549e11ee7e3b2c89b08a2fd55875d85aaf1aa217bf18d1ab0f88f959d2490606001610884565b6000546001600160a01b03163314610afe57604051633057182d60e21b815260040160405180910390fd5b6000610b0a4382610829565b90506117708261ffff161115610b885760405162461bcd60e51b815260206004820152603d60248201527f4e6f756e7344414f3a3a5f7365744d617851756f72756d566f7465734250533a60448201527f20696e76616c6964206d61782071756f72756d20766f7465732062707300000060648201526084016106c6565b805161ffff80841691161115610c155760405162461bcd60e51b815260206004820152604660248201527f4e6f756e7344414f3a3a5f7365744d617851756f72756d566f7465734250533a60448201527f206d696e2071756f72756d20766f7465732062707320677265617465722074686064820152650c2dc40dac2f60d31b608482015260a4016106c6565b60208101805161ffff8416909152610c2c82611b73565b6040805161ffff8084168252851660208201527f4bfb1235074b38f02e5cf8ba90f535905417c196a12654f65ee0584512d706429101610884565b6000546001600160a01b03163314610c9257604051633057182d60e21b815260040160405180910390fd5b61c4e08163ffffffff161115610cbb576040516388a79ca760e01b815260040160405180910390fd5b6010805463ffffffff838116680100000000000000008181026bffffffff0000000000000000198516179094556040805194909304919091168084526020840191909152917fd185da00ceb738d5e65ef6936975bcb81fe742adc63d901592003d7bc22f4dfa9101610709565b6000546001600160a01b03163314610d5357604051633057182d60e21b815260040160405180910390fd5b6000610d5f4382610829565b905060c88261ffff1610158015610d7c57506107d08261ffff1611155b610dee5760405162461bcd60e51b815260206004820152603d60248201527f4e6f756e7344414f3a3a5f7365744d696e51756f72756d566f7465734250533a60448201527f20696e76616c6964206d696e2071756f72756d20766f7465732062707300000060648201526084016106c6565b806020015161ffff168261ffff161115610e7f5760405162461bcd60e51b815260206004820152604660248201527f4e6f756e7344414f3a3a5f7365744d696e51756f72756d566f7465734250533a60448201527f206d696e2071756f72756d20766f7465732062707320677265617465722074686064820152650c2dc40dac2f60d31b608482015260a4016106c6565b805161ffff83168252610e9182611b73565b6040805161ffff8084168252851660208201527ffaeebe30d875e399189096ea49fea81bd41fe6dfc86ad3550639063219e607789101610884565b6000546001600160a01b03163314610ef757604051633057182d60e21b815260040160405180910390fd5b62127500811115610f1b57604051637762590b60e01b815260040160405180910390fd5b6202a300811015610f3f57604051633430477560e11b815260040160405180910390fd5b7ffa0345f15af4cde74f214a8800528bd12cb260c12d8669007af35d869cb6877360006016015460408051918252602082018490520160405180910390a1601655565b610f8b86610986565b610f94856117de565b610f9e84846110a6565b610fa782610ecc565b610fb081610584565b505050505050565b6000546001600160a01b03163314610fe357604051633057182d60e21b815260040160405180910390fd5b60018110158015610ff657506103e88111155b6110685760405162461bcd60e51b815260206004820152603f60248201527f4e6f756e7344414f3a3a5f73657450726f706f73616c5468726573686f6c643a60448201527f20696e76616c69642070726f706f73616c207468726573686f6c64206270730060648201526084016106c6565b600680549082905560408051828152602081018490527ffc216faa269bf440fb06aa490693f409461bde9cdcb949c7b9f2cb79589e7a589101610709565b6000546001600160a01b031633146110d157604051633057182d60e21b815260040160405180910390fd5b6110db8282611d61565b6040517f6158953ac4c84a0a8642793ade32098d1ecd12702db9ce2eb7c72c4463a8fb0790611110906012908590859061213d565b60405180910390a161112460128383611e83565b505050565b6000546001600160a01b0316331461115457604051633057182d60e21b815260040160405180910390fd5b600180546001600160a01b038381166001600160a01b03198316179092556040519116907fca4f2f25d0898edd99413412fb94012f9e54ec8142f9b093e7720646a95b16a9906107099083908590612123565b6000600301546001600160a01b031633146112125760405162461bcd60e51b815260206004820152602560248201527f4e6f756e7344414f3a3a5f6275726e5665746f506f7765723a207665746f6572604482015264206f6e6c7960d81b60648201526084016106c6565b7fc5644f3588a066b15dcf6b636b74aadca57cfaccf608d9de7d8786364b7a8d02600060030154604051611252916001600160a01b031690600090612123565b60405180910390a1600080610919565b60008080546001600160a01b0316331461128f57604051633057182d60e21b815260040160405180910390fd5b6040514790600090339083908381818185875af1925050503d80600081146112d3576040519150601f19603f3d011682016040523d82523d6000602084013e6112d8565b606091505b50506040805184815282151560208201529192507f2aeb20ed0ead73e7bc740154a0b979547bc9e00691d84a700e6454ada9fe4679910160405180910390a190925090509091565b6000600301546001600160a01b0316331461134e57604051631387214760e01b815260040160405180910390fd5b7f7ad92e57a52c4e3e83ba624622b14e3a5efa0160dd6f9a7975c43ea66bad79ea6000600e015460405161138d916001600160a01b0316908490612123565b60405180910390a1600e80546001600160a01b0319166001600160a01b0392909216919091179055565b6000546001600160a01b031633146113e257604051633057182d60e21b815260040160405180910390fd5b6010805463ffffffff83811663ffffffff1983168117909355604080519190921680825260208201939093527f581878c50ce0b9e3ff58adfe29b7a807191bef3c1623340a0ad1d0d8433ebf869101610709565b6000546001600160a01b0316331461146157604051633057182d60e21b815260040160405180910390fd5b61c4e08163ffffffff16111561148a5760405163024c1d4b60e31b815260040160405180910390fd5b6010805463ffffffff83811664010000000081810267ffffffff00000000198516179094556040805194909304919091168084526020840191909152917ff860ba522a6e820ac6577b201d9314604a19ad2e264913d8361821e3659568db9101610709565b6000600101546001600160a01b03163314801561150b57503315155b61156a5760405162461bcd60e51b815260206004820152602a60248201527f4e6f756e7344414f3a3a5f61636365707441646d696e3a2070656e64696e672060448201526961646d696e206f6e6c7960b01b60648201526084016106c6565b60008054600180546001600160a01b03198084166001600160a01b03838116918217909655911690915560405192909116917ff9ffabca9c8276e99321725bcb43fb076a6c66a54b7f21c4e8146d8519b417dc906115cb9084908490612123565b60405180910390a17fca4f2f25d0898edd99413412fb94012f9e54ec8142f9b093e7720646a95b16a9816000604051610709929190612123565b6000546001600160a01b0316331461163057604051633057182d60e21b815260040160405180910390fd5b60c88361ffff16108061164857506107d08361ffff16115b156116665760405163db8a74af60e01b815260040160405180910390fd5b6117708261ffff16111561168d5760405163143abf4360e21b815260040160405180910390fd5b8161ffff168361ffff1611156116b6576040516362c564d560e11b815260040160405180910390fd5b60006116c24382610829565b9050600060405180606001604052808661ffff1681526020018561ffff1681526020018463ffffffff1681525090506116fa81611b73565b815181516040805161ffff93841681529290911660208301527ffaeebe30d875e399189096ea49fea81bd41fe6dfc86ad3550639063219e60778910160405180910390a17f4bfb1235074b38f02e5cf8ba90f535905417c196a12654f65ee0584512d706428260200151826020015160405161178792919061ffff92831681529116602082015260400190565b60405180910390a160408083015182820151825163ffffffff9283168152911660208201527f5e3adb1066359dafa23c629f245d93543856115700821dcb4debc416f393c469910160405180910390a15050505050565b6000546001600160a01b0316331461180957604051633057182d60e21b815260040160405180910390fd5b601180546001600160a01b038381166001600160a01b03198316179092556040519116907f5f317d96631add203c522c8ecc74fd6144c936367e2205ac922331fb12b670b4906107099083908590612123565b6040805160608101825260008082526020820181905291810191909152600061189d8360405180606001604052806040815260200161229760409139611e2a565b600d85015490915060008190036118f45760405180606001604052806118c68760070154611e5a565b61ffff1681526020016118dc8760070154611e5a565b61ffff16815260006020909101529250611b6d915050565b63ffffffff8216600d860161190a6001846121e9565b8154811061191a5761191a6121fc565b600091825260209091206002909102015463ffffffff16116119ad57600d85016119456001836121e9565b81548110611955576119556121fc565b6000918252602091829020604080516060810182526002939093029091016001015461ffff8082168452620100008204169383019390935264010000000090920463ffffffff16918101919091529250611b6d915050565b8163ffffffff1685600d016000815481106119ca576119ca6121fc565b600091825260209091206002909102015463ffffffff1611156119ff5760405180606001604052806118c68760070154611e5a565b600080611a0d6001846121e9565b90505b81811115611b035760006002611a2684846121e9565b611a309190612212565b611a3a90836121e9565b9050600088600d018281548110611a5357611a536121fc565b60009182526020918290206040805180820182526002909302909101805463ffffffff9081168452825160608101845260019092015461ffff808216845262010000820416838701526401000000009004811692820192909252928201929092528051909250878216911603611ad457602001519550611b6d945050505050565b805163ffffffff80881691161015611aee57819350611afc565b611af96001836121e9565b92505b5050611a10565b86600d018281548110611b1857611b186121fc565b6000918252602091829020604080516060810182526002939093029091016001015461ffff8082168452620100008204169383019390935264010000000090920463ffffffff16918101919091529450505050505b92915050565b6000611bb4436040518060400160405280601c81526020017f626c6f636b206e756d6265722065786365656473203332206269747300000000815250611e2a565b600d549091508015801590611c01575063ffffffff8216600d611bd86001846121e9565b81548110611be857611be86121fc565b600091825260209091206002909102015463ffffffff16145b15611c8e5782600d611c146001846121e9565b81548110611c2457611c246121fc565b60009182526020918290208351600160029093029091019190910180549284015160409094015163ffffffff166401000000000267ffffffff000000001961ffff958616620100000263ffffffff1990951695909316949094179290921716919091179055505050565b5060408051808201825263ffffffff92831681526020808201948552600d805460018101825560009190915291517fd7b6990105719101dabeb77144f2a3385c8033acd3af97e9423a695e81ad1eb56002909302928301805491861663ffffffff19928316179055945180517fd7b6990105719101dabeb77144f2a3385c8033acd3af97e9423a695e81ad1eb690930180549282015191909401519094166401000000000267ffffffff000000001961ffff95861662010000029290961694909216939093179290921792909216179055565b6000819003611d6e575050565b60005b611d7c6001836121e9565b811015611124576000611d90826001612234565b90505b82811015611e2157838382818110611dad57611dad6121fc565b9050602002016020810190611dc29190611f5d565b6001600160a01b0316848484818110611ddd57611ddd6121fc565b9050602002016020810190611df29190611f5d565b6001600160a01b031603611e1957604051630254983f60e41b815260040160405180910390fd5b600101611d93565b50600101611d71565b60008163ffffffff841115611e525760405162461bcd60e51b81526004016106c69190612247565b509192915050565b600061ffff821115611e7f5760405163555abf0160e11b815260040160405180910390fd5b5090565b828054828255906000526020600020908101928215611ed6579160200282015b82811115611ed65781546001600160a01b0319166001600160a01b03843516178255602090920191600190910190611ea3565b50611e7f9291505b80821115611e7f5760008155600101611ede565b600060208284031215611f0457600080fd5b5035919050565b803563ffffffff81168114611f1f57600080fd5b919050565b600060208284031215611f3657600080fd5b611f3f82611f0b565b9392505050565b80356001600160a01b0381168114611f1f57600080fd5b600060208284031215611f6f57600080fd5b611f3f82611f46565b600080600060608486031215611f8d57600080fd5b611f9684611f46565b9250611fa460208501611f46565b9150611fb260408501611f46565b90509250925092565b803561ffff81168114611f1f57600080fd5b600060208284031215611fdf57600080fd5b611f3f82611fbb565b60008083601f840112611ffa57600080fd5b50813567ffffffffffffffff81111561201257600080fd5b6020830191508360208260051b850101111561202d57600080fd5b9250929050565b60008060008060008060a0878903121561204d57600080fd5b61205687611f46565b955061206460208801611f46565b9450604087013567ffffffffffffffff81111561208057600080fd5b61208c89828a01611fe8565b979a9699509760608101359660809091013595509350505050565b600080602083850312156120ba57600080fd5b823567ffffffffffffffff8111156120d157600080fd5b6120dd85828601611fe8565b90969095509350505050565b6000806000606084860312156120fe57600080fd5b61210784611fbb565b925061211560208501611fbb565b9150611fb260408501611f0b565b6001600160a01b0392831681529116602082015260400190565b6000604082016040835280865480835260608501915087600052602092508260002060005b828110156121875781546001600160a01b031684529284019260019182019101612162565b505050838103828501528481528590820160005b868110156121c7576001600160a01b036121b484611f46565b168252918301919083019060010161219b565b50979650505050505050565b634e487b7160e01b600052601160045260246000fd5b81810381811115611b6d57611b6d6121d3565b634e487b7160e01b600052603260045260246000fd5b60008261222f57634e487b7160e01b600052601260045260246000fd5b500490565b80820180821115611b6d57611b6d6121d3565b60006020808352835180602085015260005b8181101561227557858101830151858201604001528201612259565b506000604082860101526040601f19601f830116850101925050509291505056fe4e6f756e7344414f3a3a67657444796e616d696351756f72756d506172616d7341743a20626c6f636b206e756d62657220657863656564732033322062697473a2646970667358221220c5e5aef6847a19b009419ec27b21f32c87b71c941e50267d3a1a5da2521c32ae64736f6c63430008170033", + "nonce": "0x3", + "chainId": "0x1", + "accessList": null, + "type": null + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x89857e7b83a9aa57ade9d740ec6de5e57302eb3510327110e00e0b3b18622589", + "transactionType": "CREATE", + "contractName": "NounsDAODynamicQuorum", + "contractAddress": "0xb5aa61eff82ea7b4ea6443532df15b7d4b40c3a0", + "function": null, + "arguments": null, + "transaction": { + "from": "0x918895f466eb3cd5fb181626f8e1b2fd8a9d5192", + "to": null, + "gas": "0x3c5f4", + "value": null, + "input": "0x61027a61003a600b82828239805160001a60731461002d57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600436106100355760003560e01c8063bb2960751461003a575b600080fd5b61004d610048366004610131565b61005f565b60405190815260200160405180910390f35b6000808361006f866127106101f8565b610079919061020f565b90506000620f424082856040015163ffffffff1661009791906101f8565b6100a1919061020f565b9050600081856000015161ffff166100b99190610231565b905060006100cf866020015161ffff16836100e7565b90506100db8188610101565b98975050505050505050565b60008183106100f657816100f8565b825b90505b92915050565b600061271061011084846101f8565b6100f8919061020f565b803561ffff8116811461012c57600080fd5b919050565b600080600083850360a081121561014757600080fd5b84359350602085013592506060603f198201121561016457600080fd5b506040516060810181811067ffffffffffffffff8211171561019657634e487b7160e01b600052604160045260246000fd5b80604052506101a76040860161011a565b81526101b56060860161011a565b6020820152608085013563ffffffff811681146101d157600080fd5b604082015292959194509192509050565b634e487b7160e01b600052601160045260246000fd5b80820281158282048414176100fb576100fb6101e2565b60008261022c57634e487b7160e01b600052601260045260246000fd5b500490565b808201808211156100fb576100fb6101e256fea26469706673582212208d1cbada5250b0f0ee7f487f17b8024885b2c4a3e362b79a95a6ab87356ad76864736f6c63430008170033", + "nonce": "0x4", + "chainId": "0x1", + "accessList": null, + "type": null + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x8f40d8b469c009bde3cb810314babc483ea3e47073180ac4e43917424325f7da", + "transactionType": "CREATE", + "contractName": "NounsDAOFork", + "contractAddress": "0x3d4f1ee041c31afc0fbda4f058d34544d71eb6ad", + "function": null, + "arguments": null, + "transaction": { + "from": "0x918895f466eb3cd5fb181626f8e1b2fd8a9d5192", + "to": null, + "gas": "0x15fc5d", + "value": null, + "input": "0x61131761003a600b82828239805160001a60731461002d57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600436106100925760003560e01c8063704a3b1211610065578063704a3b12146101125780637a868d3e14610152578063aeaa6be614610172578063f667e1141461019257600080fd5b80630577a8461461009757806313d419f6146100b957806319244b17146100df5780636055f935146100f2575b600080fd5b8180156100a357600080fd5b506100b76100b2366004610efe565b6101b2565b005b6100cc6100c7366004610f4a565b6102f8565b6040519081526020015b60405180910390f35b6100cc6100ed366004610f4a565b610379565b8180156100fe57600080fd5b506100b761010d366004610efe565b6103a0565b81801561011e57600080fd5b5061013261012d366004610f4a565b6103c2565b604080516001600160a01b039384168152929091166020830152016100d6565b81801561015e57600080fd5b506100b761016d366004610f63565b61063c565b81801561017e57600080fd5b506100b761018d36600461104c565b6107e1565b81801561019e57600080fd5b506100b76101ad366004610f63565b610866565b60158301544210156101d7576040516366c8a93b60e01b815260040160405180910390fd5b6010830154604051633567f93d60e11b8152600160601b9091046001600160a01b0316908190636acff27a90610215903390879087906004016110dd565b600060405180830381600087803b15801561022f57600080fd5b505af1158015610243573d6000803e3d6000fd5b50505050336001600160a01b0316816001600160a01b031663d7e53db06040518163ffffffff1660e01b8152600401602060405180830381865afa15801561028f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102b3919061110b565b63ffffffff167f7e066a27b070725cdb5ae51be8128dc95d65af0841137f77ec895c775f69849985856040516102ea929190611138565b60405180910390a350505050565b600081601001600c9054906101000a90046001600160a01b03166001600160a01b031663aa34213b6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561034f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103739190611154565b92915050565b6000612710826017015461038c84610aa1565b6103969190611183565b610373919061119a565b60098301546103bd908490849084906001600160a01b0316610c1d565b505050565b6000806103d28360150154421090565b156103f0576040516366c8a93b60e01b815260040160405180910390fd5b600083601001600c9054906101000a90046001600160a01b031690506000816001600160a01b031663aa34213b6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561044c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104709190611154565b905061047b85610379565b811161049a57604051630698c25760e11b815260040160405180910390fd5b60008560160154426104ac91906111bc565b601187015460405163fb14694360e01b8152600481018390526001600160a01b03868116602483015292935091169063fb1469439060440160408051808303816000875af1158015610502573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061052691906111cf565b909550935061053f86868461053a83610aa1565b610ce7565b6000836001600160a01b031663c163de3d6040518163ffffffff1660e01b81526004016020604051808303816000875af1158015610581573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105a5919061110b565b6013880180546001600160a01b038981166001600160a01b0319928316811790935560148b018054918a1691909216811790915560158a0185905560408051928352602083019190915281018490526060810185905290915063ffffffff8216907fb924f7ec9fa839e53ec987276a1a33b95a0aa0796ca86204f365925ac2dbded99060800160405180910390a250505050915091565b6015870154421015610661576040516366c8a93b60e01b815260040160405180910390fd5b6010870154600160601b90046001600160a01b031660005b8681101561072357600a8901546001600160a01b03166342842e0e33848b8b868181106106a8576106a8611209565b6040516001600160e01b031960e088901b1681526001600160a01b03958616600482015294909316602485015250602090910201356044820152606401600060405180830381600087803b1580156106ff57600080fd5b505af1158015610713573d6000803e3d6000fd5b5050600190920191506106799050565b50336001600160a01b0316816001600160a01b031663d7e53db06040518163ffffffff1660e01b8152600401602060405180830381865afa15801561076c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610790919061110b565b63ffffffff167f9a9bbe8a8a2c2b1e1d690cccd211b60ef1d2976f404800ed20604e57d3ed0f2d8989898989896040516107cf9695949392919061121f565b60405180910390a35050505050505050565b60098401546001600160a01b03908116908216036108125760405163c37a1e1760e01b815260040160405180910390fd5b61081e84848484610c1d565b604080518381526001600160a01b03831660208201527f855244575056ebffdfb115e332dfa96f1cd148bfe5bf486758fdd2d55b6fe9eb91015b60405180910390a150505050565b6015870154421061088a57604051635a7d97a760e11b815260040160405180910390fd5b6010870154600988015460138901546001600160a01b03600160601b909304831692918216916108c1918b91168961053a83610aa1565b60005b8781101561096e57600a8a01546001600160a01b03166323b872dd33848c8c868181106108f3576108f3611209565b6040516001600160e01b031960e088901b1681526001600160a01b03958616600482015294909316602485015250602090910201356044820152606401600060405180830381600087803b15801561094a57600080fd5b505af115801561095e573d6000803e3d6000fd5b5050600190920191506108c49050565b5060148901546040516374ea764760e01b81526001600160a01b03909116906374ea7647906109a59033908c908c906004016110dd565b600060405180830381600087803b1580156109bf57600080fd5b505af11580156109d3573d6000803e3d6000fd5b50505050336001600160a01b03166001836001600160a01b031663d7e53db06040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a21573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a45919061110b565b610a4f919061127e565b63ffffffff167f96ca5dab079aba8ed43c71a25c6090b5bce0e3f9ebcb4080816655b7a2d5a36f8a8a8a8a8a8a604051610a8e9695949392919061121f565b60405180910390a3505050505050505050565b600081601001600c9054906101000a90046001600160a01b03166001600160a01b0316639b3c1e226040518163ffffffff1660e01b8152600401602060405180830381865afa158015610af8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b1c9190611154565b600a83015460098401546040516370a0823160e01b81526001600160a01b0391821660048201529116906370a0823190602401602060405180830381865afa158015610b6c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b909190611154565b83600a0160009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610be5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c099190611154565b610c1391906112a2565b61037391906112a2565b83546001600160a01b03163314610c4757604051633057182d60e21b815260040160405180910390fd5b601084015460405163341f601360e21b8152600160601b9091046001600160a01b03169063d07d804c90610c83908690869086906004016112b5565b600060405180830381600087803b158015610c9d57600080fd5b505af1158015610cb1573d6000803e3d6000fd5b505050507e5508ab2be53c6629a9db1afe9702076dc2c4c4f344d60e711a315891d7141e838383604051610858939291906112b5565b60098401546001600160a01b0316600082610d03858431611183565b610d0d919061119a565b6040516364a197f360e01b81526001600160a01b03878116600483015260248201839052919250908316906364a197f390604401600060405180830381600087803b158015610d5b57600080fd5b505af1158015610d6f573d6000803e3d6000fd5b50505050601286015460005b81811015610ea8576000886012018281548110610d9a57610d9a611209565b60009182526020822001546040516370a0823160e01b81526001600160a01b03888116600483015290911692508790899084906370a0823190602401602060405180830381865afa158015610df3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e179190611154565b610e219190611183565b610e2b919061119a565b90508015610e9e576040516323e5d69960e21b81526001600160a01b038a81166004830152838116602483015260448201839052871690638f975a6490606401600060405180830381600087803b158015610e8557600080fd5b505af1158015610e99573d6000803e3d6000fd5b505050505b5050600101610d7b565b5050505050505050565b60008083601f840112610ec457600080fd5b50813567ffffffffffffffff811115610edc57600080fd5b6020830191508360208260051b8501011115610ef757600080fd5b9250929050565b600080600060408486031215610f1357600080fd5b83359250602084013567ffffffffffffffff811115610f3157600080fd5b610f3d86828701610eb2565b9497909650939450505050565b600060208284031215610f5c57600080fd5b5035919050565b60008060008060008060006080888a031215610f7e57600080fd5b87359650602088013567ffffffffffffffff80821115610f9d57600080fd5b610fa98b838c01610eb2565b909850965060408a0135915080821115610fc257600080fd5b610fce8b838c01610eb2565b909650945060608a0135915080821115610fe757600080fd5b818a0191508a601f830112610ffb57600080fd5b81358181111561100a57600080fd5b8b602082850101111561101c57600080fd5b60208301945080935050505092959891949750929550565b6001600160a01b038116811461104957600080fd5b50565b6000806000806060858703121561106257600080fd5b84359350602085013567ffffffffffffffff81111561108057600080fd5b61108c87828801610eb2565b90945092505060408501356110a081611034565b939692955090935050565b81835260006001600160fb1b038311156110c457600080fd5b8260051b80836020870137939093016020019392505050565b6001600160a01b038416815260406020820181905260009061110290830184866110ab565b95945050505050565b60006020828403121561111d57600080fd5b815163ffffffff8116811461113157600080fd5b9392505050565b60208152600061114c6020830184866110ab565b949350505050565b60006020828403121561116657600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b80820281158282048414176103735761037361116d565b6000826111b757634e487b7160e01b600052601260045260246000fd5b500490565b808201808211156103735761037361116d565b600080604083850312156111e257600080fd5b82516111ed81611034565b60208401519092506111fe81611034565b809150509250929050565b634e487b7160e01b600052603260045260246000fd5b60608152600061123360608301888a6110ab565b82810360208401526112468187896110ab565b90508281036040840152838152838560208301376000602085830101526020601f19601f860116820101915050979650505050505050565b63ffffffff82811682821603908082111561129b5761129b61116d565b5092915050565b818103818111156103735761037361116d565b6040815260006112c96040830185876110ab565b905060018060a01b038316602083015294935050505056fea2646970667358221220fd802a6052690f91ee05466d04b1d277dd3a3f33cdfc92bf23e0ec0373c36d9a64736f6c63430008170033", + "nonce": "0x5", + "chainId": "0x1", + "accessList": null, + "type": null + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0xa603f6aebe14018d59b50528a7c8fa404c310e7a23e016e114a33fadfe838f2a", + "transactionType": "CREATE", + "contractName": "NounsDAOProposals", + "contractAddress": "0xac6eefcc699047856c07c8679e1339903bd5ffcc", + "function": null, + "arguments": null, + "transaction": { + "from": "0x918895f466eb3cd5fb181626f8e1b2fd8a9d5192", + "to": null, + "gas": "0x4ffaae", + "value": null, + "input": "0x6147f961003a600b82828239805160001a60731461002d57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600436106101155760003560e01c806383478b43116100ac578063b0a3fc381161007b578063b0a3fc38146102ac578063b2faf4d4146102cc578063b7aa3e57146102ec578063ddb639831461030c578063f9df1e191461032c57600080fd5b806383478b431461021e578063853b94a01461023e57806392be51d814610265578063ac982f381461028557600080fd5b80633ce52dbe116100e85780633ce52dbe1461019e5780635e6ab1ac146101be57806373d0ed2f146101de5780637b55bff3146101fe57600080fd5b806320606b701461011a57806320660f531461015457806336e7048a14610174578063370d35771461017c575b600080fd5b6101417f8cad95687ba82c2ce50e74f7b754645e5117c3a5bec8151c0726d5857980a86681565b6040519081526020015b60405180910390f35b81801561016057600080fd5b5061014161016f3660046138a0565b61034c565b610141600a81565b81801561018857600080fd5b5061019c61019736600461394f565b6104bc565b005b8180156101aa57600080fd5b5061019c6101b936600461394f565b6104ea565b8180156101ca57600080fd5b5061019c6101d936600461394f565b6109b1565b6101f16101ec36600461394f565b610cd5565b60405161014b9190613987565b81801561020a57600080fd5b5061019c6102193660046139af565b610cea565b81801561022a57600080fd5b5061019c610239366004613ab8565b610d4e565b6101417fd4eafb6bc770edecb5da52765bc3f50af948bfe1b8344cf115f8ee7fefe55ec781565b61027861027336600461394f565b610daf565b60405161014b9190613b9c565b6101417fe5a9e6d2702042f3612beac0f605312204baddec2d19d1338da7e37e6c67d6ee81565b8180156102b857600080fd5b5061019c6102c7366004613ca3565b610f2c565b8180156102d857600080fd5b5061019c6102e736600461394f565b610f87565b8180156102f857600080fd5b5061019c610307366004613d25565b61118f565b61031f61031a36600461394f565b611211565b60405161014b9190613db5565b81801561033857600080fd5b5061019c610347366004613ee4565b61144f565b6000845160000361037057604051637a4783fb60e01b815260040160405180910390fd5b61037984611738565b6103a36040518060600160405280600063ffffffff16815260200160008152602001600081525090565b60088701546103b3906001613fb8565b600888018190556103c3906117cf565b63ffffffff1681526103d487611838565b602082018190526103e69088906119b4565b6040820181905281516020830151600092610407928b929091908a896119c4565b90506000806104238a8a8a8a886000015163ffffffff16611b8d565b91509150805160000361044957604051637a4783fb60e01b815260040160405180910390fd5b8360400151821161046d5760405163ead8241560e01b815260040160405180910390fd5b805161048290601285019060208401906132b4565b506104a7838261049f87602001518e611e5290919063ffffffff16565b8b8b8b611e6c565b5050905163ffffffff16979650505050505050565b6000818152600b830160205260408120906104d78483611f46565b90506104e4848383611f7e565b50505050565b60006104f683836121b2565b9050600281600a81111561050c5761050c613971565b14806105295750600381600a81111561052757610527613971565b145b806105455750600681600a81111561054357610543613971565b145b806105615750600781600a81111561055f5761055f613971565b145b8061057d5750600881600a81111561057b5761057b613971565b145b1561059b57604051635598baf360e01b815260040160405180910390fd5b6000828152600b840160205260408120600180820154600a87015492936001600160a01b039182169390911691829063782d6fe19085906105dc9043613fcb565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401602060405180830381865afa158015610625573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106499190613fde565b6001600160601b031690506000336001600160a01b0316846001600160a01b03161490506000856012018054806020026020016040519081016040528092919081815260200182805480156106c757602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116106a9575b5050505050905060005b81518110156107d257828061071057508181815181106106f3576106f361400e565b60200260200101516001600160a01b0316336001600160a01b0316145b9250846001600160a01b031663782d6fe18383815181106107335761073361400e565b60200260200101516001436107489190613fcb565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401602060405180830381865afa158015610791573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107b59190613fde565b6107c8906001600160601b031685613fb8565b93506001016106d1565b5081806107e3575085600201548311155b6108475760405162461bcd60e51b815260206004820152602a60248201527f4e6f756e7344414f3a3a63616e63656c3a2070726f706f7365722061626f7665604482015269081d1a1c995cda1bdb1960b21b60648201526084015b60405180910390fd5b600e8601805460ff1916600117905560006108628a88611f46565b905060005b600588015481101561097157816001600160a01b031663591fcdfe8960050183815481106108975761089761400e565b60009182526020909120015460068b0180546001600160a01b0390921691859081106108c5576108c561400e565b90600052602060002001548b60070185815481106108e5576108e561400e565b906000526020600020018c60080186815481106109045761090461400e565b906000526020600020018d600401546040518663ffffffff1660e01b81526004016109339594939291906140db565b600060405180830381600087803b15801561094d57600080fd5b505af1158015610961573d6000803e3d6000fd5b5050600190920191506108679050565b506040518981527f789cf55be980739dad1d0699b93b58e806b51c9d96619bfa8fe0a28abaa7b30c9060200160405180910390a150505050505050505050565b60046109bd83836121b2565b600a8111156109ce576109ce613971565b14610a415760405162461bcd60e51b815260206004820152603f60248201527f4e6f756e7344414f3a3a71756575653a2070726f706f73616c2063616e206f6e60448201527f6c79206265207175657565642069662069742069732073756363656564656400606482015260840161083e565b6000818152600b83016020526040812090610a5c8483611f46565b90506000816001600160a01b0316636a42b8f86040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a9e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ac29190614127565b610acc9042613fb8565b905060005b6005840154811015610c8d57610c8583856005018381548110610af657610af661400e565b6000918252602090912001546006870180546001600160a01b039092169185908110610b2457610b2461400e565b9060005260206000200154876007018581548110610b4457610b4461400e565b906000526020600020018054610b5990614024565b80601f0160208091040260200160405190810160405280929190818152602001828054610b8590614024565b8015610bd25780601f10610ba757610100808354040283529160200191610bd2565b820191906000526020600020905b815481529060010190602001808311610bb557829003601f168201915b5050505050886008018681548110610bec57610bec61400e565b906000526020600020018054610c0190614024565b80601f0160208091040260200160405190810160405280929190818152602001828054610c2d90614024565b8015610c7a5780601f10610c4f57610100808354040283529160200191610c7a565b820191906000526020600020905b815481529060010190602001808311610c5d57829003601f168201915b5050505050876123ab565b600101610ad1565b506004830181905560408051858152602081018390527f9a2e42fd6722813d69113e7d0079d3d940171428df7373df9c7f7617cfda2892910160405180910390a15050505050565b6000610ce183836121b2565b90505b92915050565b610cf8888888888888612554565b336001600160a01b0316877fd92cc1350c3c114b08bfa9ca07e42b8d07adf3c440ac299943edfbfb9be890ac888888888888604051610d3c9695949392919061421b565b60405180910390a35050505050505050565b610d5c878787878787612554565b336001600160a01b0316867f2588d794bdaac5e181a3efca6937bf6bac4e2f42f43dcfcf0492b3d8b54be0658787878787604051610d9e95949392919061429d565b60405180910390a350505050505050565b610e37604051806101e001604052806000815260200160006001600160a01b03168152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160001515815260200160001515815260200160001515815260200160008152602001600081525090565b6000828152600b8401602090815260409182902082516101e081018452815463ffffffff90811680835260018401546001600160a01b031694830194909452600283015494820194909452909290916060830191610e979188916125f916565b81526004830154602082015260098301546040820152600a8301546060820152600b8301546080820152600c83015460a0820152600d83015460c0820152600e83015460ff808216151560e0840152610100808304821615159084015262010000909104161515610120820152601083015461014082015260119092015463ffffffff16610160909201919091529392505050565b6000858152600b870160205260409020610f47878783612652565b336001600160a01b0316867fb326c35bcac6caacafa6cd1190bb9dc1a4e0aad7a7985e193818797dfbec990587878787604051610d9e9493929190614327565b60038201546001600160a01b0316610fb257604051631efc808d60e31b815260040160405180910390fd5b60038201546001600160a01b03163314610fdf57604051631387214760e01b815260040160405180910390fd5b6007610feb83836121b2565b600a811115610ffc57610ffc613971565b0361101a57604051636c0a12d560e01b815260040160405180910390fd5b6000818152600b830160205260408120600e8101805461ff001916610100179055906110468483611f46565b905060005b600583015481101561115557816001600160a01b031663591fcdfe84600501838154811061107b5761107b61400e565b6000918252602090912001546006860180546001600160a01b0390921691859081106110a9576110a961400e565b90600052602060002001548660070185815481106110c9576110c961400e565b906000526020600020018760080186815481106110e8576110e861400e565b9060005260206000200188600401546040518663ffffffff1660e01b81526004016111179594939291906140db565b600060405180830381600087803b15801561113157600080fd5b505af1158015611145573d6000803e3d6000fd5b50506001909201915061104b9050565b506040518381527fde0cea2a3a0097cc3d981d40c375407760e85bc9c5e69aea449ac3885f8615c69060200160405180910390a150505050565b600082826040516111a192919061434e565b60408051918290038220336000818152600f89016020908152848220848352905292909220805460ff191660011790559250907f45f194850d9c26cfb50dad5456a1c64997b6a4d461d0159f372282ba183d854d90611203908690869061435e565b60405180910390a250505050565b6112b76040518061026001604052806000815260200160006001600160a01b03168152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160001515815260200160001515815260200160001515815260200160008152602001600081526020016060815260200160008152602001600081526020016000151581525090565b6000828152600b84016020908152604091829020825161026081018452815463ffffffff90811680835260018401546001600160a01b0316948301949094526002830154948201949094529092909160608301916113179188916125f916565b815260048301546020808301919091526009840154604080840191909152600a8501546060840152600b8501546080840152600c85015460a0840152600d85015460c0840152600e85015460ff808216151560e08601526101008083048216151590860152620100009091041615156101208401526010850154610140840152601185015463ffffffff1661016084015260128501805482518185028101850190935280835261018090940193919290919083018282801561140257602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116113e4575b505050918352505060118301546001600160401b03600160401b820481166020840152600160801b90910416604082015260139092015460ff161515606090920191909152905092915050565b61145883611738565b835160000361147a57604051637a4783fb60e01b815260040160405180910390fd5b6000858152600b870160205260409020600a61149688886121b2565b600a8111156114a7576114a7613971565b146114c5576040516339abb30760e21b815260040160405180910390fd5b60018101546001600160a01b031633146114f257604051631d6b368d60e01b815260040160405180910390fd5b60008160120180548060200260200160405190810160405280929190818152602001828054801561154c57602002820191906000526020600020905b81546001600160a01b0316815260019091019060200180831161152e575b5050505050905080518651146115755760405163b92ba76160e01b815260040160405180910390fd5b6000876115833388886126e2565b604051602001611594929190614372565b604051602081830303815290604052905060005b8751811015611666576115f68a838a84815181106115c8576115c861400e565b60200260200101517fe5a9e6d2702042f3612beac0f605312204baddec2d19d1338da7e37e6c67d6ee61292d565b8781815181106116085761160861400e565b6020026020010151602001516001600160a01b031683828151811061162f5761162f61400e565b60200260200101516001600160a01b03161461165e57604051631d6b368d60e01b815260040160405180910390fd5b6001016115a8565b508551805161167f9160058601916020909101906132b4565b5060208087015180516116989260068701920190613315565b50604086015180516116b4916007860191602090910190613350565b50606086015180516116d09160088601916020909101906133a2565b50336001600160a01b0316887fd92cc1350c3c114b08bfa9ca07e42b8d07adf3c440ac299943edfbfb9be890ac886000015189602001518a604001518b606001518b8b6040516117259695949392919061421b565b60405180910390a3505050505050505050565b602081015151815151141580611755575060408101515181515114155b80611767575060608101515181515114155b156117855760405163ccb0ce3f60e01b815260040160405180910390fd5b8051516000036117a857604051630f24cd7360e01b815260040160405180910390fd5b805151600a10156117cc576040516308e3b1eb60e11b815260040160405180910390fd5b50565b600063ffffffff8211156118345760405162461bcd60e51b815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203360448201526532206269747360d01b606482015260840161083e565b5090565b600081601001600c9054906101000a90046001600160a01b03166001600160a01b0316639b3c1e226040518163ffffffff1660e01b8152600401602060405180830381865afa15801561188f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118b39190614127565b600a83015460098401546040516370a0823160e01b81526001600160a01b0391821660048201529116906370a0823190602401602060405180830381865afa158015611903573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119279190614127565b83600a0160009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561197c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119a09190614127565b6119aa9190613fcb565b610ce49190613fcb565b6000610ce18360060154836129f1565b601086015460009081906119ee906119e990600160401b900463ffffffff1643613fb8565b612a0a565b905060008860040154826001600160401b0316611a0b9190613fb8565b90506000896005015482611a1f9190613fb8565b63ffffffff808b166000818152600b8e01602090815260409091208054938a166401000000000267ffffffffffffffff199094169092179290921781556001810180546001600160a01b03191633179055600281018b905588518051919750929350611a9192600588019201906132b4565b506020808701518051611aaa9260068801920190613315565b5060408601518051611ac6916007870191602090910190613350565b5060608601518051611ae29160088701916020909101906133a2565b5060098401829055600a840181905560108401879055611b01436117cf565b60118501805463ffffffff191663ffffffff92909216919091179055611b26426117cf565b6011850180546001600160401b03909516600160401b026fffffffffffffffff00000000000000001963ffffffff9390931664010000000002929092166fffffffffffffffffffffffff000000001990951694909417179092555090979650505050505050565b600a8501546000906060906001600160a01b031682611bad3388886126e2565b905087516001600160401b03811115611bc857611bc861347d565b604051908082528060200260200182016040528015611bf1578160200160208202803683370190505b5092506000805b8951811015611d7b57611c468b848c8481518110611c1857611c1861400e565b60200260200101517fd4eafb6bc770edecb5da52765bc3f50af948bfe1b8344cf115f8ee7fefe55ec761292d565b60008a8281518110611c5a57611c5a61400e565b6020026020010151602001519050611c728c82612a72565b60006001600160a01b03861663782d6fe183611c8f600143613fcb565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401602060405180830381865afa158015611cd8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cfc9190613fde565b6001600160601b0316905080600003611d16575050611d73565b818785611d2281614398565b965081518110611d3457611d3461400e565b6001600160a01b039283166020918202929092018101919091529083166000908152600c8f0190915260409020899055611d6e8189613fb8565b975050505b600101611bf8565b508851811015611d89578084525b611d938a33612a72565b336000818152600c8c01602052604090208790556001600160a01b0384169063782d6fe190611dc3600143613fcb565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401602060405180830381865afa158015611e0c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e309190613fde565b611e43906001600160601b031686613fb8565b94505050509550959350505050565b6000610ce1611e618443612b28565b5161ffff16836129f1565b855483516020850151604080870151606088015160098c0154600a8d015493517f7d84a6263ae0d98d3329bd7b46bb4e8d6f98cd35a7adb45c274c8b7fd5ebd5e097611ecf9763ffffffff90911696339691959094909390929091908c906143b1565b60405180910390a185546011870154600288015460405163ffffffff808616947fd9d12651716feaac10e3b79bd2960ad42ebfd84969b71a2e226ec99972a8712e94611f369491909216928b926001600160401b03600160401b9091041691908b9061444f565b60405180910390a2505050505050565b601381015460009060ff1615611f6a575060188201546001600160a01b0316610ce4565b5060098201546001600160a01b0316610ce4565b60058254611f9390859063ffffffff166121b2565b600a811115611fa457611fa4613971565b14612019576040805162461bcd60e51b81526020600482015260248101919091527f4e6f756e7344414f3a3a657865637574653a2070726f706f73616c2063616e2060448201527f6f6e6c7920626520657865637574656420696620697420697320717565756564606482015260840161083e565b601583015442101561203e57604051633183594360e21b815260040160405180910390fd5b600e8201805462ff000019166201000017905560005b600583015481101561217057816001600160a01b0316630825f38f8460050183815481106120845761208461400e565b6000918252602090912001546006860180546001600160a01b0390921691859081106120b2576120b261400e565b90600052602060002001548660070185815481106120d2576120d261400e565b906000526020600020018760080186815481106120f1576120f161400e565b9060005260206000200188600401546040518663ffffffff1660e01b81526004016121209594939291906140db565b6000604051808303816000875af115801561213f573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526121679190810190614494565b50600101612054565b50815460405163ffffffff90911681527f712ae1383f79ac853f8d882153778e0260ef8f03b504e2866e0593e04d2b291f9060200160405180910390a1505050565b600081836008015410156122145760405162461bcd60e51b8152602060048201526024808201527f4e6f756e7344414f3a3a73746174653a20696e76616c69642070726f706f73616044820152631b081a5960e21b606482015260840161083e565b6000828152600b840160205260409020600e810154610100900460ff1615612240576008915050610ce4565b600e81015460ff1615612257576002915050610ce4565b6011810154600160401b90046001600160401b0316431161227c57600a915050610ce4565b80600901544311612291576000915050610ce4565b80600a015443116122a6576001915050610ce4565b6011810154600160801b90046001600160401b031643116122cb576009915050610ce4565b6122d58482612e3d565b156122e4576003915050610ce4565b80600401546000036122fa576004915050610ce4565b600e81015462010000900460ff1615612317576007915050610ce4565b6123218482611f46565b6001600160a01b031663c1a287e26040518163ffffffff1660e01b8152600401602060405180830381865afa15801561235e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123829190614127565b81600401546123919190613fb8565b42106123a1576006915050610ce4565b6005915050610ce4565b856001600160a01b031663f2b0653786868686866040516020016123d395949392919061450a565b604051602081830303815290604052805190602001206040518263ffffffff1660e01b815260040161240791815260200190565b602060405180830381865afa158015612424573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124489190614543565b156124d45760405162461bcd60e51b815260206004820152605060248201527f4e6f756e7344414f3a3a71756575654f72526576657274496e7465726e616c3a60448201527f206964656e746963616c2070726f706f73616c20616374696f6e20616c72656160648201526f6479207175657565642061742065746160801b608482015260a40161083e565b604051633a66f90160e01b81526001600160a01b03871690633a66f90190612508908890889088908890889060040161450a565b6020604051808303816000875af1158015612527573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061254b9190614127565b50505050505050565b61257d604051806080016040528086815260200185815260200184815260200183815250611738565b6000858152600b870160205260409020612598878783612652565b84516125ad90600583019060208801906132b4565b5083516125c39060068301906020870190613315565b5082516125d99060078301906020860190613350565b5081516125ef90600883019060208501906133a2565b5050505050505050565b6000818152600b8301602052604081206010810154820361261f57600301549050610ce4565b600c8101546010820154601183015461264a92919061264590889063ffffffff16612b28565b612e73565b949350505050565b600a61265e84846121b2565b600a81111561266f5761266f613971565b1461268d576040516339abb30760e21b815260040160405180910390fd5b60018101546001600160a01b031633146126ba57604051631d6b368d60e01b815260040160405180910390fd5b6012810154156126dd57604051630e13f93360e11b815260040160405180910390fd5b505050565b606060008360400151516001600160401b038111156127035761270361347d565b60405190808252806020026020018201604052801561272c578160200160208202803683370190505b50905060005b84604001515181101561278957846040015181815181106127555761275561400e565b6020026020010151805190602001208282815181106127765761277661400e565b6020908102919091010152600101612732565b5060008460600151516001600160401b038111156127a9576127a961347d565b6040519080825280602002602001820160405280156127d2578160200160208202803683370190505b50905060005b85606001515181101561282f57856060015181815181106127fb576127fb61400e565b60200260200101518051906020012082828151811061281c5761281c61400e565b60209081029190910101526001016127d8565b508451604051879161284391602001614565565b60405160208183030381529060405280519060200120866020015160405160200161286e91906145a4565b604051602081830303815290604052805190602001208460405160200161289591906145a4565b60405160208183030381529060405280519060200120846040516020016128bc91906145a4565b60408051601f1981840301815282825280516020918201208b518c8301206001600160a01b0390981691840191909152908201949094526060810192909252608082015260a081019190915260c081019190915260e001604051602081830303815290604052925050509392505050565b81518051602091820120818401516001600160a01b03166000908152600f870183526040808220838352909352919091205460ff161561298057604051634260f73960e01b815260040160405180910390fd5b60006129928386866040015130612efb565b90506129a78460200151828660000151612ff3565b6129c457604051638baa579f60e01b815260040160405180910390fd5b83604001514211156129e957604051630819bdcd60e01b815260040160405180910390fd5b505050505050565b6000612710612a0084846145ce565b610ce191906145e5565b60006001600160401b038211156118345760405162461bcd60e51b815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203660448201526534206269747360d01b606482015260840161083e565b6001600160a01b0381166000908152600c8301602052604090205480156126dd576000612a9f84836121b2565b9050600981600a811115612ab557612ab5613971565b1480612ad25750600181600a811115612ad057612ad0613971565b145b80612aee5750600081600a811115612aec57612aec613971565b145b80612b0a5750600a81600a811115612b0857612b08613971565b145b156104e4576040516306bee79560e01b815260040160405180910390fd5b60408051606081018252600080825260208201819052918101919091526000612b698360405180606001604052806040815260200161478460409139613054565b600d8501549091506000819003612bc0576040518060600160405280612b928760070154613084565b61ffff168152602001612ba88760070154613084565b61ffff16815260006020909101529250610ce4915050565b63ffffffff8216600d8601612bd6600184613fcb565b81548110612be657612be661400e565b600091825260209091206002909102015463ffffffff1611612c7957600d8501612c11600183613fcb565b81548110612c2157612c2161400e565b6000918252602091829020604080516060810182526002939093029091016001015461ffff8082168452620100008204169383019390935264010000000090920463ffffffff16918101919091529250610ce4915050565b8163ffffffff1685600d01600081548110612c9657612c9661400e565b600091825260209091206002909102015463ffffffff161115612ccb576040518060600160405280612b928760070154613084565b600080612cd9600184613fcb565b90505b81811115612dcf5760006002612cf28484613fcb565b612cfc91906145e5565b612d069083613fcb565b9050600088600d018281548110612d1f57612d1f61400e565b60009182526020918290206040805180820182526002909302909101805463ffffffff9081168452825160608101845260019092015461ffff808216845262010000820416838701526401000000009004811692820192909252928201929092528051909250878216911603612da057602001519550610ce4945050505050565b805163ffffffff80881691161015612dba57819350612dc8565b612dc5600183613fcb565b92505b5050612cdc565b86600d018281548110612de457612de461400e565b6000918252602091829020604080516060810182526002939093029091016001015461ffff8082168452620100008204169383019390935264010000000090920463ffffffff1691810191909152979650505050505050565b600b810154600c820154600091908111158061264a57508254612e6b90859063ffffffff908116906125f916565b119392505050565b60008083612e83866127106145ce565b612e8d91906145e5565b90506000620f424082856040015163ffffffff16612eab91906145ce565b612eb591906145e5565b9050600081856000015161ffff16612ecd9190613fb8565b90506000612ee3866020015161ffff16836130a9565b9050612eef81886129f1565b98975050505050505050565b600080858585604051602001612f1393929190614607565b60408051601f198184030181528282528051602091820120838301835260098452684e6f756e732044414f60b81b9382019390935281517f8cad95687ba82c2ce50e74f7b754645e5117c3a5bec8151c0726d5857980a866818301527fe1dd93b3612547b4bb7c3d429f3df8508d84f5a4f63b5e2e44340b94698e6b3b818401524660608201526001600160a01b0387166080808301919091528351808303909101815260a0820193849052805192019190912061190160f01b835260a2820181905260c29091018390526042909120919250905b979650505050505050565b600080600061300285856130bf565b9092509050600081600481111561301b5761301b613971565b1480156130395750856001600160a01b0316826001600160a01b0316145b8061304a575061304a868686613104565b9695505050505050565b60008163ffffffff84111561307c5760405162461bcd60e51b815260040161083e9190614634565b509192915050565b600061ffff8211156118345760405163555abf0160e11b815260040160405180910390fd5b60008183106130b85781610ce1565b5090919050565b60008082516041036130f55760208301516040840151606085015160001a6130e9878285856131f0565b945094505050506130fd565b506000905060025b9250929050565b6000806000856001600160a01b0316631626ba7e60e01b868660405160240161312e929190614647565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b031990941693909317909252905161316c9190614660565b600060405180830381855afa9150503d80600081146131a7576040519150601f19603f3d011682016040523d82523d6000602084013e6131ac565b606091505b50915091508180156131c057506020815110155b801561304a57508051630b135d3f60e11b906131e59083016020908101908401614127565b149695505050505050565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a083111561322757506000905060036132ab565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa15801561327b573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b0381166132a4576000600192509250506132ab565b9150600090505b94509492505050565b828054828255906000526020600020908101928215613309579160200282015b8281111561330957825182546001600160a01b0319166001600160a01b039091161782556020909201916001909101906132d4565b506118349291506133f4565b828054828255906000526020600020908101928215613309579160200282015b82811115613309578251825591602001919060010190613335565b828054828255906000526020600020908101928215613396579160200282015b82811115613396578251829061338690826146c4565b5091602001919060010190613370565b50611834929150613409565b8280548282559060005260206000209081019282156133e8579160200282015b828111156133e857825182906133d890826146c4565b50916020019190600101906133c2565b50611834929150613426565b5b8082111561183457600081556001016133f5565b8082111561183457600061341d8282613443565b50600101613409565b8082111561183457600061343a8282613443565b50600101613426565b50805461344f90614024565b6000825580601f1061345f575050565b601f0160209004906000526020600020908101906117cc91906133f4565b634e487b7160e01b600052604160045260246000fd5b604051606081016001600160401b03811182821017156134b5576134b561347d565b60405290565b604051608081016001600160401b03811182821017156134b5576134b561347d565b604051601f8201601f191681016001600160401b03811182821017156135055761350561347d565b604052919050565b60006001600160401b038211156135265761352661347d565b5060051b60200190565b60006001600160401b038211156135495761354961347d565b50601f01601f191660200190565b600082601f83011261356857600080fd5b813561357b61357682613530565b6134dd565b81815284602083860101111561359057600080fd5b816020850160208301376000918101602001919091529392505050565b80356001600160a01b03811681146135c457600080fd5b919050565b600082601f8301126135da57600080fd5b813560206135ea6135768361350d565b82815260059290921b8401810191818101908684111561360957600080fd5b8286015b848110156136995780356001600160401b038082111561362d5760008081fd5b908801906060828b03601f19018113156136475760008081fd5b61364f613493565b87840135838111156136615760008081fd5b61366f8d8a83880101613557565b825250604092506136818385016135ad565b8189015292013590820152835291830191830161360d565b509695505050505050565b600082601f8301126136b557600080fd5b813560206136c56135768361350d565b8083825260208201915060208460051b8701019350868411156136e757600080fd5b602086015b84811015613699576136fd816135ad565b83529183019183016136ec565b600082601f83011261371b57600080fd5b8135602061372b6135768361350d565b8083825260208201915060208460051b87010193508684111561374d57600080fd5b602086015b848110156136995780358352918301918301613752565b600082601f83011261377a57600080fd5b8135602061378a6135768361350d565b82815260059290921b840181019181810190868411156137a957600080fd5b8286015b848110156136995780356001600160401b038111156137cc5760008081fd5b6137da8986838b0101613557565b8452509183019183016137ad565b6000608082840312156137fa57600080fd5b6138026134bb565b905081356001600160401b038082111561381b57600080fd5b613827858386016136a4565b8352602084013591508082111561383d57600080fd5b6138498583860161370a565b6020840152604084013591508082111561386257600080fd5b61386e85838601613769565b6040840152606084013591508082111561388757600080fd5b5061389484828501613769565b60608301525092915050565b600080600080600060a086880312156138b857600080fd5b8535945060208601356001600160401b03808211156138d657600080fd5b6138e289838a016135c9565b955060408801359150808211156138f857600080fd5b61390489838a016137e8565b9450606088013591508082111561391a57600080fd5b5061392788828901613557565b925050608086013563ffffffff8116811461394157600080fd5b809150509295509295909350565b6000806040838503121561396257600080fd5b50508035926020909101359150565b634e487b7160e01b600052602160045260246000fd5b60208101600b83106139a957634e487b7160e01b600052602160045260246000fd5b91905290565b600080600080600080600080610100898b0312156139cc57600080fd5b883597506020890135965060408901356001600160401b03808211156139f157600080fd5b6139fd8c838d016136a4565b975060608b0135915080821115613a1357600080fd5b613a1f8c838d0161370a565b965060808b0135915080821115613a3557600080fd5b613a418c838d01613769565b955060a08b0135915080821115613a5757600080fd5b613a638c838d01613769565b945060c08b0135915080821115613a7957600080fd5b613a858c838d01613557565b935060e08b0135915080821115613a9b57600080fd5b50613aa88b828c01613557565b9150509295985092959890939650565b600080600080600080600060e0888a031215613ad357600080fd5b873596506020880135955060408801356001600160401b0380821115613af857600080fd5b613b048b838c016136a4565b965060608a0135915080821115613b1a57600080fd5b613b268b838c0161370a565b955060808a0135915080821115613b3c57600080fd5b613b488b838c01613769565b945060a08a0135915080821115613b5e57600080fd5b613b6a8b838c01613769565b935060c08a0135915080821115613b8057600080fd5b50613b8d8a828b01613557565b91505092959891949750929550565b815181526020808301516101e0830191613bc0908401826001600160a01b03169052565b5060408301516040830152606083015160608301526080830151608083015260a083015160a083015260c083015160c083015260e083015160e083015261010080840151818401525061012080840151818401525061014080840151613c298285018215159052565b505061016083810151151590830152610180808401511515908301526101a080840151908301526101c092830151929091019190915290565b60008083601f840112613c7457600080fd5b5081356001600160401b03811115613c8b57600080fd5b6020830191508360208285010111156130fd57600080fd5b60008060008060008060808789031215613cbc57600080fd5b863595506020870135945060408701356001600160401b0380821115613ce157600080fd5b613ced8a838b01613c62565b90965094506060890135915080821115613d0657600080fd5b50613d1389828a01613c62565b979a9699509497509295939492505050565b600080600060408486031215613d3a57600080fd5b8335925060208401356001600160401b03811115613d5757600080fd5b613d6386828701613c62565b9497909650939450505050565b60008151808452602080850194506020840160005b83811015613daa5781516001600160a01b031687529582019590820190600101613d85565b509495945050505050565b602081528151602082015260006020830151613ddc60408401826001600160a01b03169052565b506040830151606083015260608301516080830152608083015160a083015260a083015160c083015260c083015160e083015260e0830151610100818185015280850151915050610120818185015280850151915050610140818185015280850151915050610160613e518185018315159052565b8401519050610180613e668482018315159052565b84015190506101a0613e7b8482018315159052565b8401516101c0848101919091528401516101e08085019190915284015161026061020080860182905291925090613eb6610280860184613d70565b9086015161022086810191909152860151610240808701919091529095015115159301929092525090919050565b60008060008060008060c08789031215613efd57600080fd5b863595506020870135945060408701356001600160401b0380821115613f2257600080fd5b613f2e8a838b016135c9565b95506060890135915080821115613f4457600080fd5b613f508a838b016137e8565b94506080890135915080821115613f6657600080fd5b613f728a838b01613557565b935060a0890135915080821115613f8857600080fd5b50613f9589828a01613557565b9150509295509295509295565b634e487b7160e01b600052601160045260246000fd5b80820180821115610ce457610ce4613fa2565b81810381811115610ce457610ce4613fa2565b600060208284031215613ff057600080fd5b81516001600160601b038116811461400757600080fd5b9392505050565b634e487b7160e01b600052603260045260246000fd5b600181811c9082168061403857607f821691505b60208210810361405857634e487b7160e01b600052602260045260246000fd5b50919050565b6000815461406b81614024565b80855260206001838116801561408857600181146140a2576140d0565b60ff1985168884015283151560051b8801830195506140d0565b866000528260002060005b858110156140c85781548a82018601529083019084016140ad565b890184019650505b505050505092915050565b60018060a01b038616815284602082015260a06040820152600061410260a083018661405e565b8281036060840152614114818661405e565b9150508260808301529695505050505050565b60006020828403121561413957600080fd5b5051919050565b60008151808452602080850194506020840160005b83811015613daa57815187529582019590820190600101614155565b60005b8381101561418c578181015183820152602001614174565b50506000910152565b600081518084526141ad816020860160208601614171565b601f01601f19169290920160200192915050565b60008282518085526020808601955060208260051b8401016020860160005b8481101561420e57601f198684030189526141fc838351614195565b988401989250908301906001016141e0565b5090979650505050505050565b60c08152600061422e60c0830189613d70565b82810360208401526142408189614140565b9050828103604084015261425481886141c1565b9050828103606084015261426881876141c1565b9050828103608084015261427c8186614195565b905082810360a08401526142908185614195565b9998505050505050505050565b60a0815260006142b060a0830188613d70565b82810360208401526142c28188614140565b905082810360408401526142d681876141c1565b905082810360608401526142ea81866141c1565b90508281036080840152612eef8185614195565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b60408152600061433b6040830186886142fe565b8281036020840152612fe88185876142fe565b8183823760009101908152919050565b60208152600061264a6020830184866142fe565b8281526000825161438a816020850160208701614171565b919091016020019392505050565b6000600182016143aa576143aa613fa2565b5060010190565b63ffffffff8a1681526001600160a01b0389166020820152610120604082018190526000906143e28382018b613d70565b905082810360608401526143f6818a614140565b9050828103608084015261440a81896141c1565b905082810360a084015261441e81886141c1565b90508560c08401528460e084015282810361010084015261443f8185614195565b9c9b505050505050505050505050565b63ffffffff8616815260a06020820152600061446e60a0830187613d70565b6001600160401b0395909516604083015250606081019290925260809091015292915050565b6000602082840312156144a657600080fd5b81516001600160401b038111156144bc57600080fd5b8201601f810184136144cd57600080fd5b80516144db61357682613530565b8181528560208385010111156144f057600080fd5b614501826020830160208601614171565b95945050505050565b60018060a01b038616815284602082015260a06040820152600061453160a0830186614195565b82810360608401526141148186614195565b60006020828403121561455557600080fd5b8151801515811461400757600080fd5b815160009082906020808601845b838110156145985781516001600160a01b031685529382019390820190600101614573565b50929695505050505050565b815160009082906020808601845b83811015614598578151855293820193908201906001016145b2565b8082028115828204841417610ce457610ce4613fa2565b60008261460257634e487b7160e01b600052601260045260246000fd5b500490565b8381526000835161461f816020850160208801614171565b60209201918201929092526040019392505050565b602081526000610ce16020830184614195565b82815260406020820152600061264a6040830184614195565b60008251614672818460208701614171565b9190910192915050565b601f8211156126dd576000816000526020600020601f850160051c810160208610156146a55750805b601f850160051c820191505b818110156129e9578281556001016146b1565b81516001600160401b038111156146dd576146dd61347d565b6146f1816146eb8454614024565b8461467c565b602080601f831160018114614726576000841561470e5750858301515b600019600386901b1c1916600185901b1785556129e9565b600085815260208120601f198616915b8281101561475557888601518255948401946001909101908401614736565b50858210156147735787850151600019600388901b60f8161c191681555b5050505050600190811b0190555056fe4e6f756e7344414f3a3a67657444796e616d696351756f72756d506172616d7341743a20626c6f636b206e756d62657220657863656564732033322062697473a26469706673582212203d27194f160b95bf2f25018dac840393c3bd014f71918b4913b59d1cbc642ae964736f6c63430008170033", + "nonce": "0x6", + "chainId": "0x1", + "accessList": null, + "type": null + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x3234f140996918456dfdfee0ed2e8081f9b971a9c004b24b29cc4d9aa7a96e40", + "transactionType": "CREATE", + "contractName": "NounsDAOVotes", + "contractAddress": "0x3e4e4d094a73aac69ff6592cda602b76134951d6", + "function": null, + "arguments": null, + "transaction": { + "from": "0x918895f466eb3cd5fb181626f8e1b2fd8a9d5192", + "to": null, + "gas": "0x1dc81a", + "value": null, + "input": "0x611a3361003a600b82828239805160001a60731461002d57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600436106100be5760003560e01c8063b73a99c71161007b578063b73a99c714610187578063bc4cd084146101a7578063deaaa7cc146101b3578063e105d84a146101da578063f57e66d1146101fa578063fbfee8761461021a57600080fd5b8063042bc3de146100c357806306fdde03146100e057806320606b70146101155780633be8ef3f1461013c57806350de7cf614610145578063aabb220a14610167575b600080fd5b6100cd62030d4081565b6040519081526020015b60405180910390f35b610108604051806040016040528060098152602001684e6f756e732044414f60b81b81525081565b6040516100d791906115ba565b6100cd7f8cad95687ba82c2ce50e74f7b754645e5117c3a5bec8151c0726d5857980a86681565b6100cd618ca081565b81801561015157600080fd5b50610165610160366004611640565b610225565b005b81801561017357600080fd5b506101656101823660046116b7565b610271565b81801561019357600080fd5b506101656101a23660046116ec565b6102ce565b6100cd642e90edd00081565b6100cd7f150214d74d59b7d1e90c73fc22ef3d991dd0a76b046543d4d80ab92d2a50328f81565b8180156101e657600080fd5b506101656101f5366004611754565b610310565b81801561020657600080fd5b5061016561021536600461179a565b610332565b6100cd637735940081565b61026986868686868080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250889250610593915050565b505050505050565b336000805160206119de8339815191528383610291878584846000610641565b6040805193845260ff90921660208401526001600160601b03169082015260806060820181905260009082015260a00160405180910390a2505050565b336000805160206119de83398151915285856102ee898584846000610641565b86866040516103019594939291906117f2565b60405180910390a25050505050565b61032c8484846040518060200160405280600081525085610593565b50505050565b60408051808201825260098152684e6f756e732044414f60b81b60209182015281517f8cad95687ba82c2ce50e74f7b754645e5117c3a5bec8151c0726d5857980a866818301527fe1dd93b3612547b4bb7c3d429f3df8508d84f5a4f63b5e2e44340b94698e6b3b81840152466060820152306080808301919091528351808303909101815260a0820184528051908301207f150214d74d59b7d1e90c73fc22ef3d991dd0a76b046543d4d80ab92d2a50328f60c083015260e0820189905260ff8816610100808401919091528451808403909101815261012083019094528351939092019290922061190160f01b6101408401526101428301829052610162830181905290916000906101820160408051601f198184030181528282528051602091820120600080855291840180845281905260ff8a169284019290925260608301889052608083018790529092509060019060a0016020604051602081039080840390855afa1580156104ab573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b0381166105265760405162461bcd60e51b815260206004820152602a60248201527f4e6f756e7344414f3a3a63617374566f746542795369673a20696e76616c6964604482015269207369676e617475726560b01b60648201526084015b60405180910390fd5b806001600160a01b03166000805160206119de8339815191528a8a61054f8e868f8f6000610641565b6040805193845260ff90921660208401526001600160601b03169082015260806060820181905260009082015260a00160405180910390a250505050505050505050565b60005a905060006105a78733888887610641565b9050336001600160a01b03166000805160206119de833981519152878784886040516105d69493929190611842565b60405180910390a263ffffffff8316156106205760405163ffffffff841690879033907f651cc9d78606507fdcfc4f37ec37a744d612b1d8f5a73564190577c4f0edb0b690600090a45b6001600160601b038116156106385761063882610804565b50505050505050565b60008061064e87866108f2565b9050600181600a8111156106645761066461187d565b0361067c5761067587868887610afa565b915061071f565b600981600a8111156106905761069061187d565b036106c25760ff8416156106b757604051639aeea66b60e01b815260040160405180910390fd5b610675878688610ea5565b60405162461bcd60e51b815260206004820152602c60248201527f4e6f756e7344414f3a3a63617374566f7465496e7465726e616c3a20766f746960448201526b1b99c81a5cc818db1bdcd95960a21b606482015260840161051d565b6000858152600b88016020908152604080832063ffffffff808816855260149091018352928190208151808301835290548085168252640100000000900484169281019290925280518082019091528151919290918291610782918791166118a9565b63ffffffff1681526020018260200151600161079e91906118c9565b63ffffffff9081169091526000978852600b90990160209081526040808920968b168952601490960181529490962086518154979095015189166401000000000267ffffffffffffffff1990971694909816939093179490941790955550929392505050565b476000819003610812575050565b600061082348642e90edd000611022565b905060006108373a63773594008401611022565b9050600061084e618ca05a87030162030d40611022565b9050600061085e82840286611022565b604051909150600090329083908381818185875af1925050503d80600081146108a3576040519150601f19603f3d011682016040523d82523d6000602084013e6108a8565b606091505b505060408051848152821515602082015291925032917ffabef36fd46c4c3a6ad676521be5367a4dfdbf3faa68d8e826003b1752d68f4f910160405180910390a250505050505050565b600081836008015410156109545760405162461bcd60e51b8152602060048201526024808201527f4e6f756e7344414f3a3a73746174653a20696e76616c69642070726f706f73616044820152631b081a5960e21b606482015260840161051d565b6000828152600b840160205260409020600e810154610100900460ff1615610980576008915050610af4565b600e81015460ff1615610997576002915050610af4565b601181015468010000000000000000900467ffffffffffffffff1643116109c257600a915050610af4565b806009015443116109d7576000915050610af4565b80600a015443116109ec576001915050610af4565b6011810154600160801b900467ffffffffffffffff164311610a12576009915050610af4565b610a1c848261103a565b15610a2b576003915050610af4565b8060040154600003610a41576004915050610af4565b600e81015462010000900460ff1615610a5e576007915050610af4565b610a688482611073565b6001600160a01b031663c1a287e26040518163ffffffff1660e01b8152600401602060405180830381865afa158015610aa5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ac991906118e6565b8160040154610ad891906118ff565b4210610ae8576006915050610af4565b6005915050610af4565b505b92915050565b600060028260ff161115610b765760405162461bcd60e51b815260206004820152603f60248201527f4e6f756e7344414f3a3a63617374566f7465447572696e67566f74696e67506560448201527f72696f64496e7465726e616c3a20696e76616c696420766f7465207479706500606482015260840161051d565b6000848152600b8601602090815260408083206001600160a01b0387168452600f8101909252909120805460ff1615610c215760405162461bcd60e51b815260206004820152604160248201527f4e6f756e7344414f3a3a63617374566f7465447572696e67566f74696e67506560448201527f72696f64496e7465726e616c3a20766f74657220616c726561647920766f74656064820152601960fa1b608482015260a40161051d565b600a870154600983015460405163782d6fe160e01b81526000926001600160a01b03169163782d6fe191610c6d918a916004016001600160a01b03929092168252602082015260400190565b602060405180830381865afa158015610c8a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cae9190611912565b905060008560ff16600103610cdf576010890154600a85015463ffffffff90911690610cdb90439061193b565b1090505b60008115610cf457610cf18a8661103a565b90505b8660ff16600003610d2257826001600160601b031685600c0154610d1891906118ff565b600c860155610d7a565b8660ff16600103610d5057826001600160601b031685600b0154610d4691906118ff565b600b860155610d7a565b8660ff16600203610d7a57826001600160601b031685600d0154610d7491906118ff565b600d8601555b818015610d845750805b8015610da357506011850154600160801b900467ffffffffffffffff16155b8015610db65750610db48a8661103a565b155b15610e595760108a0154600a860154610de791610de29164010000000090910463ffffffff16906118ff565b6110ab565b60118601805467ffffffffffffffff60801b1916600160801b67ffffffffffffffff93841681029190911791829055875460405191909204909216825263ffffffff16907f6553d98dd06f98670b24f69f718cdf9c8ec8e1cc42fb58b9c7908731322273479060200160405180910390a25b505081546001600160601b03821662010000026dffffffffffffffffffffffff00001960ff88166101000261ffff19909316929092176001179190911617909155915050949350505050565b6000828152600b8401602090815260408083206001600160a01b0385168452600f81019092528220805460ff1615610f375760405162461bcd60e51b815260206004820152602f60248201527f4e6f756e7344414f3a3a63617374566f7465496e7465726e616c3a20766f746560448201526e1c88185b1c9958591e481d9bdd1959608a1b606482015260840161051d565b600a860154600983015460405163782d6fe160e01b81526000926001600160a01b03169163782d6fe191610f839189916004016001600160a01b03929092168252602082015260400190565b602060405180830381865afa158015610fa0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fc49190611912565b825461ff001960ff196001600160601b038416620100008102919091166dffffffffffffffffffffffff00ff1990931692909217600117168455600c85015491925061100f916118ff565b600c909301929092555090509392505050565b60008183106110315781611033565b825b9392505050565b600b810154600c820154600091908111158061106b5750825461106890859063ffffffff9081169061111816565b81105b949350505050565b601381015460009060ff1615611097575060188201546001600160a01b0316610af4565b5060098201546001600160a01b0316610af4565b600067ffffffffffffffff8211156111145760405162461bcd60e51b815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203660448201526534206269747360d01b606482015260840161051d565b5090565b6000818152600b8301602052604081206010810154820361113e57600301549050610af4565b600c8101546010820154601183015461106b92919061116490889063ffffffff16611169565b61147e565b604080516060810182526000808252602082018190529181019190915260006111aa8360405180606001604052806040815260200161199e60409139611506565b600d85015490915060008190036112015760405180606001604052806111d38760070154611536565b61ffff1681526020016111e98760070154611536565b61ffff16815260006020909101529250610af4915050565b63ffffffff8216600d860161121760018461193b565b815481106112275761122761194e565b600091825260209091206002909102015463ffffffff16116112ba57600d850161125260018361193b565b815481106112625761126261194e565b6000918252602091829020604080516060810182526002939093029091016001015461ffff8082168452620100008204169383019390935264010000000090920463ffffffff16918101919091529250610af4915050565b8163ffffffff1685600d016000815481106112d7576112d761194e565b600091825260209091206002909102015463ffffffff16111561130c5760405180606001604052806111d38760070154611536565b60008061131a60018461193b565b90505b818111156114105760006002611333848461193b565b61133d9190611964565b611347908361193b565b9050600088600d0182815481106113605761136061194e565b60009182526020918290206040805180820182526002909302909101805463ffffffff9081168452825160608101845260019092015461ffff8082168452620100008204168387015264010000000090048116928201929092529282019290925280519092508782169116036113e157602001519550610af4945050505050565b805163ffffffff808816911610156113fb57819350611409565b61140660018361193b565b92505b505061131d565b86600d0182815481106114255761142561194e565b6000918252602091829020604080516060810182526002939093029091016001015461ffff8082168452620100008204169383019390935264010000000090920463ffffffff1691810191909152979650505050505050565b6000808361148e86612710611986565b6114989190611964565b90506000620f424082856040015163ffffffff166114b69190611986565b6114c09190611964565b9050600081856000015161ffff166114d891906118ff565b905060006114ee866020015161ffff1683611022565b90506114fa818861155b565b98975050505050505050565b60008163ffffffff84111561152e5760405162461bcd60e51b815260040161051d91906115ba565b509192915050565b600061ffff8211156111145760405163555abf0160e11b815260040160405180910390fd5b600061271061156a8484611986565b6110339190611964565b6000815180845260005b8181101561159a5760208185018101518683018201520161157e565b506000602082860101526020601f19601f83011685010191505092915050565b6020815260006110336020830184611574565b803560ff811681146115de57600080fd5b919050565b60008083601f8401126115f557600080fd5b50813567ffffffffffffffff81111561160d57600080fd5b60208301915083602082850101111561162557600080fd5b9250929050565b803563ffffffff811681146115de57600080fd5b60008060008060008060a0878903121561165957600080fd5b8635955060208701359450611670604088016115cd565b9350606087013567ffffffffffffffff81111561168c57600080fd5b61169889828a016115e3565b90945092506116ab90506080880161162c565b90509295509295509295565b6000806000606084860312156116cc57600080fd5b83359250602084013591506116e3604085016115cd565b90509250925092565b60008060008060006080868803121561170457600080fd5b853594506020860135935061171b604087016115cd565b9250606086013567ffffffffffffffff81111561173757600080fd5b611743888289016115e3565b969995985093965092949392505050565b6000806000806080858703121561176a57600080fd5b8435935060208501359250611781604086016115cd565b915061178f6060860161162c565b905092959194509250565b60008060008060008060c087890312156117b357600080fd5b86359550602087013594506117ca604088016115cd565b93506117d8606088016115cd565b92506080870135915060a087013590509295509295509295565b85815260ff851660208201526001600160601b038416604082015260806060820152816080820152818360a0830137600081830160a090810191909152601f909201601f19160101949350505050565b84815260ff841660208201526001600160601b03831660408201526080606082015260006118736080830184611574565b9695505050505050565b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052601160045260246000fd5b6001600160601b03818116838216019080821115610af257610af2611893565b63ffffffff818116838216019080821115610af257610af2611893565b6000602082840312156118f857600080fd5b5051919050565b80820180821115610af457610af4611893565b60006020828403121561192457600080fd5b81516001600160601b038116811461103357600080fd5b81810381811115610af457610af4611893565b634e487b7160e01b600052603260045260246000fd5b60008261198157634e487b7160e01b600052601260045260246000fd5b500490565b8082028115828204841417610af457610af461189356fe4e6f756e7344414f3a3a67657444796e616d696351756f72756d506172616d7341743a20626c6f636b206e756d62657220657863656564732033322062697473b8e138887d0aa13bab447e82de9d5c1777041ecd21ca36ba824ff1e6c07ddda4a264697066735822122043105a1adbc23b09950f1109a24d3d90a2f0b2ecc9d47ae2033b4ca57273b9bb64736f6c63430008170033", + "nonce": "0x7", + "chainId": "0x1", + "accessList": null, + "type": null + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x7c7453c2143ccf8e68988aa6bfd0bf9f8c6eee1ba6c193090e466af34f669428", + "transactionType": "CREATE", + "contractName": "NounsDAOLogicV4", + "contractAddress": "0xa23e8a919d29d74ee24d909d80f4bc8778d656d1", + "function": null, + "arguments": null, + "transaction": { + "from": "0x918895f466eb3cd5fb181626f8e1b2fd8a9d5192", + "to": null, + "gas": "0x66a8ca", + "value": "0x0", + "input": "0x608060405234801561001057600080fd5b50615cac80620000216000396000f3fe6080604052600436106104405760003560e01c80637d17aa3a11610234578063c37522d41161012e578063da9427c4116100b6578063e48083fe1161007a578063e48083fe14610bd8578063ea3ecd0f14610d64578063f32293d214610d79578063f851a44014610d8e578063fe0d94c114610dac57610447565b8063da9427c414610c87578063da95691a14610ca7578063ddf0b00914610cc7578063e23a9a5214610ce7578063e2742e1814610d3757610447565b8063d27dd112116100fd578063d27dd11214610c01578063d33219b414610c21578063d8bff44014610c3f578063d93150be14610c5d578063da35c66414610c7257610447565b8063c37522d414610b96578063c3dd69eb14610bb8578063c82fbd0814610bd8578063cd0d9eac14610bec57610447565b806397242b8e116101bc578063aa0e23c711610180578063aa0e23c714610b07578063abb308b214610b34578063b112626314610ab1578063b58131b014610b61578063b5cd5bfa14610b7657610447565b806397242b8e14610a715780639a0dfb5314610a91578063a64e024a14610ab1578063a67d063514610ac7578063a9cf82f014610ae557610447565b806383cce0e11161020357806383cce0e1146109e457806384d1d199146109f95780638f1314b614610a1e5780638f1447d914610a3357806390f8c2f414610a5357610447565b80637d17aa3a146109725780637f5ef445146109945780637fa230bd146109af5780638136730f146109c457610447565b80633e2733341161034557806355ce73b1116102cd5780637217024c116102915780637217024c146108cb57806377388b70146108eb5780637757d18d146109205780637b3c71d31461093e5780637bdbe4d01461095e57610447565b806355ce73b1146108295780635678138814610849578063590c1f161461086957806364c0599514610889578063705cb335146108a957610447565b806344fac8f61161031457806344fac8f61461078757806347f4a077146107a757806349e857ea146107d457806353349413146107f45780635408e7f21461080957610447565b80633e273334146107055780633e4f49e61461071a5780633fde324d1461074757806340e58ee51461076757610447565b806328aa53e4116103c857806336a3b5781161039757806336a3b5781461067b57806338b1c2f6146106905780633932abb1146106b05780633b66c516146106c55780633bccf4fd146106e557610447565b806328aa53e4146105d95780632a4fa9fe146105f95780632de45f1814610619578063328dd9821461064b57610447565b806316f1b8cf1161040f57806316f1b8cf1461053757806317977c61146105575780631d28dec71461058d5780631e7b5d3a146105af578063215809ca146105c457610447565b8063013cf08b146104ad57806302a251a3146104e35780630f7b1f081461050257806314a67ea41461052257610447565b3661044757005b60003660606104a173d7c7c3c447df757a77c81fcff07f10bb22d98f4a6000368080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610dcc92505050565b80519350602001915050f35b3480156104b957600080fd5b506104cd6104c8366004613b3f565b610dfa565b6040516104da9190613b58565b60405180910390f35b3480156104ef57600080fd5b506005545b6040519081526020016104da565b34801561050e57600080fd5b506104f461051d366004613b3f565b610efe565b34801561052e57600080fd5b506006546104f4565b34801561054357600080fd5b506104f4610552366004613fa1565b610f0a565b34801561056357600080fd5b506104f4610572366004614095565b6001600160a01b03166000908152600c602052604090205490565b34801561059957600080fd5b506105ad6105a8366004613b3f565b610f27565b005b3480156105bb57600080fd5b506103e86104f4565b3480156105d057600080fd5b50611c206104f4565b3480156105e557600080fd5b506105ad6105f43660046140b2565b610f95565b34801561060557600080fd5b506104f4610614366004614174565b611408565b34801561062557600080fd5b50600a546001600160a01b03165b6040516001600160a01b0390911681526020016104da565b34801561065757600080fd5b5061066b610666366004613b3f565b611442565b6040516104da9493929190614374565b34801561068757600080fd5b506104f4611461565b34801561069c57600080fd5b506104f46106ab3660046143c1565b6114de565b3480156106bc57600080fd5b506004546104f4565b3480156106d157600080fd5b506104f46106e0366004614174565b611522565b3480156106f157600080fd5b506105ad6107003660046144a3565b61155c565b34801561071157600080fd5b506104f46115ed565b34801561072657600080fd5b5061073a610735366004613b3f565b611604565b6040516104da9190614507565b34801561075357600080fd5b506105ad610762366004614577565b611682565b34801561077357600080fd5b506105ad610782366004613b3f565b6116f2565b34801561079357600080fd5b506105ad6107a23660046145b8565b611731565b3480156107b357600080fd5b506107c76107c2366004613b3f565b611780565b6040516104da91906145e4565b3480156107e057600080fd5b506105ad6107ef366004614658565b6117a8565b34801561080057600080fd5b506016546104f4565b34801561081557600080fd5b506105ad61082436600461468d565b6117e4565b34801561083557600080fd5b506105ad6108443660046146c4565b611860565b34801561085557600080fd5b506105ad6108643660046145b8565b6118d3565b34801561087557600080fd5b506105ad61088436600461471a565b61191b565b34801561089557600080fd5b506105ad6108a43660046147b3565b61195f565b3480156108b557600080fd5b50601054600160201b900463ffffffff166104f4565b3480156108d757600080fd5b506104f46108e636600461480c565b6119d7565b3480156108f757600080fd5b50610900611a84565b604080516001600160a01b039384168152929091166020830152016104da565b34801561092c57600080fd5b506011546001600160a01b0316610633565b34801561094a57600080fd5b506105ad6109593660046147b3565b611b04565b34801561096a57600080fd5b50600a6104f4565b34801561097e57600080fd5b50601054600160401b900463ffffffff166104f4565b3480156109a057600080fd5b5060105463ffffffff166104f4565b3480156109bb57600080fd5b506104f4611b44565b3480156109d057600080fd5b506105ad6109df366004614912565b611b5b565b3480156109f057600080fd5b506007546104f4565b348015610a0557600080fd5b50601054600160601b90046001600160a01b0316610633565b348015610a2a57600080fd5b506104f4611b9d565b348015610a3f57600080fd5b506105ad610a4e366004614980565b611ba9565b348015610a5f57600080fd5b506018546001600160a01b0316610633565b348015610a7d57600080fd5b506105ad610a8c3660046149bc565b611bfd565b348015610a9d57600080fd5b506104f4610aac366004614af2565b611c97565b348015610abd57600080fd5b50620189c06104f4565b348015610ad357600080fd5b50600e546001600160a01b0316610633565b348015610af157600080fd5b50610afa611d20565b6040516104da9190614baa565b348015610b1357600080fd5b50610b27610b22366004614c06565b611dc5565b6040516104da9190614cd8565b348015610b4057600080fd5b50610b54610b4f366004613b3f565b611dd8565b6040516104da9190614d9f565b348015610b6d57600080fd5b506104f4611e84565b348015610b8257600080fd5b506105ad610b9136600461471a565b611e99565b348015610ba257600080fd5b50610bab611edd565b6040516104da9190614dad565b348015610bc457600080fd5b506105ad610bd3366004614dc0565b611f42565b348015610be457600080fd5b5060016104f4565b348015610bf857600080fd5b506104f4611f84565b348015610c0d57600080fd5b506105ad610c1c366004614658565b611fbf565b348015610c2d57600080fd5b506009546001600160a01b0316610633565b348015610c4b57600080fd5b506003546001600160a01b0316610633565b348015610c6957600080fd5b506015546104f4565b348015610c7e57600080fd5b506008546104f4565b348015610c9357600080fd5b506105ad610ca2366004614e39565b611ffb565b348015610cb357600080fd5b506104f4610cc23660046143c1565b612041565b348015610cd357600080fd5b506105ad610ce2366004613b3f565b612052565b348015610cf357600080fd5b50610d07610d02366004614f38565b612091565b6040805182511515815260208084015160ff1690820152918101516001600160601b0316908201526060016104da565b348015610d4357600080fd5b50610d57610d52366004613b3f565b61211d565b6040516104da9190614f68565b348015610d7057600080fd5b506019546104f4565b348015610d8557600080fd5b506017546104f4565b348015610d9a57600080fd5b506000546001600160a01b0316610633565b348015610db857600080fd5b506105ad610dc7366004613b3f565b612242565b6060610df18383604051806060016040528060278152602001615c1060279139612281565b90505b92915050565b610e82604051806101e001604052806000815260200160006001600160a01b03168152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160001515815260200160001515815260200160001515815260200160008152602001600081525090565b604051631257ca3b60e31b8152600060048201526024810183905273ac6eefcc699047856c07c8679e1339903bd5ffcc906392be51d8906044016101e060405180830381865af4158015610eda573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610df491906150ad565b6000610df48183612350565b6000610f1c87878787878760006119d7565b979650505050505050565b604051632cbebd3560e21b8152600060048201526024810182905273ac6eefcc699047856c07c8679e1339903bd5ffcc9063b2faf4d4906044015b60006040518083038186803b158015610f7a57600080fd5b505af4158015610f8e573d6000803e3d6000fd5b5050505050565b6009546001600160a01b031615610fbf57604051630205737f60e61b815260040160405180910390fd5b6000546001600160a01b03163314610fea57604051633057182d60e21b815260040160405180910390fd5b6001600160a01b03871661101157604051637330d04160e11b815260040160405180910390fd5b6001600160a01b0386166110385760405163d2ef0d7160e01b815260040160405180910390fd5b6040516303a8b66360e21b81528235600482015273d7c7c3c447df757a77c81fcff07f10bb22d98f4a90630ea2d98c9060240160006040518083038186803b15801561108357600080fd5b505af4158015611097573d6000803e3d6000fd5b5050604051630efd8dad60e11b81526020850135600482015273d7c7c3c447df757a77c81fcff07f10bb22d98f4a9250631dfb1b5a915060240160006040518083038186803b1580156110e957600080fd5b505af41580156110fd573d6000803e3d6000fd5b5050604080516397d048e560e01b815290850135600482015273d7c7c3c447df757a77c81fcff07f10bb22d98f4a92506397d048e5915060240160006040518083038186803b15801561114f57600080fd5b505af4158015611163573d6000803e3d6000fd5b5050600980546001600160a01b03199081166001600160a01b038c811691909117909255600a805482168b8416179055601080546001600160601b0316600160601b8b851602179055601180548216898416179055600380549091169187169190911790555073d7c7c3c447df757a77c81fcff07f10bb22d98f4a905063ec91deda6111f26020840184615186565b6112026040850160208601615186565b61121260608601604087016151a1565b6040516001600160e01b031960e086901b16815261ffff938416600482015292909116602483015263ffffffff16604482015260640160006040518083038186803b15801561126057600080fd5b505af4158015611274573d6000803e3d6000fd5b5050505073d7c7c3c447df757a77c81fcff07f10bb22d98f4a63e25607728360600160208101906112a591906151a1565b6040516001600160e01b031960e084901b16815263ffffffff91909116600482015260240160006040518083038186803b1580156112e257600080fd5b505af41580156112f6573d6000803e3d6000fd5b5050505073d7c7c3c447df757a77c81fcff07f10bb22d98f4a63e5eb5abf83608001602081019061132791906151a1565b6040516001600160e01b031960e084901b16815263ffffffff91909116600482015260240160006040518083038186803b15801561136457600080fd5b505af4158015611378573d6000803e3d6000fd5b5050505073d7c7c3c447df757a77c81fcff07f10bb22d98f4a6374b157b88360a00160208101906113a991906151a1565b6040516001600160e01b031960e084901b16815263ffffffff9190911660048201526024015b60006040518083038186803b1580156113e757600080fd5b505af41580156113fb573d6000803e3d6000fd5b5050505050505050505050565b6000610f1c604051806080016040528089815260200188815260200187815260200186815250848460006123a9909392919063ffffffff16565b60608080806114526000866124fa565b93509350935093509193509193565b6040516319244b1760e01b815260006004820181905290733d4f1ee041c31afc0fbda4f058d34544d71eb6ad906319244b17906024015b602060405180830381865af41580156114b5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114d991906151bc565b905090565b60006115186040518060800160405280888152602001878152602001868152602001858152508360008061278f909392919063ffffffff16565b9695505050505050565b6000610f1c6040518060800160405280898152602001888152602001878152602001868152508484600061278f909392919063ffffffff16565b60405163f57e66d160e01b8152600060048201526024810186905260ff8086166044830152841660648201526084810183905260a48101829052733e4e4d094a73aac69ff6592cda602b76134951d69063f57e66d19060c4015b60006040518083038186803b1580156115ce57600080fd5b505af41580156115e2573d6000803e3d6000fd5b505050505050505050565b60006114d96115fc6000612806565b600090612982565b6040516373d0ed2f60e01b8152600060048201819052602482018390529073ac6eefcc699047856c07c8679e1339903bd5ffcc906373d0ed2f90604401602060405180830381865af415801561165e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610df491906151d5565b60405163b7aa3e5760e01b815273ac6eefcc699047856c07c8679e1339903bd5ffcc9063b7aa3e57906116be906000908690869060040161521f565b60006040518083038186803b1580156116d657600080fd5b505af41580156116ea573d6000803e3d6000fd5b505050505050565b604051631e7296df60e11b8152600060048201526024810182905273ac6eefcc699047856c07c8679e1339903bd5ffcc90633ce52dbe90604401610f62565b604051637082ec2560e11b81526000600482018190526024820184905260ff831660448301526064820152733e4e4d094a73aac69ff6592cda602b76134951d69063e105d84a906084016116be565b6040805160608101825260008082526020820181905291810191909152610df460008361299c565b6040516302bbd42360e11b8152733d4f1ee041c31afc0fbda4f058d34544d71eb6ad90630577a846906116be9060009086908690600401615274565b6040516383478b4360e01b815273ac6eefcc699047856c07c8679e1339903bd5ffcc906383478b4390611828906000908a908a908a908a908a908a9060040161528e565b60006040518083038186803b15801561184057600080fd5b505af4158015611854573d6000803e3d6000fd5b50505050505050505050565b60405163575535f360e11b8152733d4f1ee041c31afc0fbda4f058d34544d71eb6ad9063aeaa6be69061189e90600090879087908790600401615309565b60006040518083038186803b1580156118b657600080fd5b505af41580156118ca573d6000803e3d6000fd5b50505050505050565b60405163555d910560e11b8152600060048201526024810183905260ff82166044820152733e4e4d094a73aac69ff6592cda602b76134951d69063aabb220a906064016116be565b604051633d43469f60e11b8152733d4f1ee041c31afc0fbda4f058d34544d71eb6ad90637a868d3e90611828906000908a908a908a908a908a908a9060040161533c565b60405163286f3e7b60e11b8152733e4e4d094a73aac69ff6592cda602b76134951d6906350de7cf6906119a1906000908890889088908890859060040161537e565b60006040518083038186803b1580156119b957600080fd5b505af41580156119cd573d6000803e3d6000fd5b5050505050505050565b60408051608081018252878152602081018790528082018690526060810185905290516320660f5360e01b815260009173ac6eefcc699047856c07c8679e1339903bd5ffcc916320660f5391611a379185918d9189908990600401615516565b602060405180830381865af4158015611a54573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a7891906151bc565b98975050505050505050565b6040516338251d8960e11b8152600060048201819052908190733d4f1ee041c31afc0fbda4f058d34544d71eb6ad9063704a3b12906024016040805180830381865af4158015611ad8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611afc919061556e565b915091509091565b60405163b73a99c760e01b8152733e4e4d094a73aac69ff6592cda602b76134951d69063b73a99c7906119a190600090889088908890889060040161559d565b60006114d9611b536000612806565b600090612cae565b60405163286f3e7b60e11b8152733e4e4d094a73aac69ff6592cda602b76134951d6906350de7cf6906115b6906000908990899089908990899060040161537e565b60006114d96000612806565b604051637082ec2560e11b8152600060048201526024810184905260ff8316604482015263ffffffff82166064820152733e4e4d094a73aac69ff6592cda602b76134951d69063e105d84a9060840161189e565b604080516080810182528781526020810187905280820186905260608101859052905163f9df1e1960e01b815273ac6eefcc699047856c07c8679e1339903bd5ffcc9163f9df1e1991611c5d916000918d918d91899089906004016155c6565b60006040518083038186803b158015611c7557600080fd5b505af4158015611c89573d6000803e3d6000fd5b505050505050505050505050565b60405163bb29607560e01b815260009073b5aa61eff82ea7b4ea6443532df15b7d4b40c3a09063bb29607590611cd59087908790879060040161562c565b602060405180830381865af4158015611cf2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d1691906151bc565b90505b9392505050565b60606000600d01805480602002602001604051908101604052809291908181526020016000905b82821015611dbc57600084815260209081902060408051808201825260028602909201805463ffffffff9081168452825160608101845260019283015461ffff80821683526201000082041682880152600160201b900490911692810192909252828401919091529083529092019101611d47565b50505050905090565b6060611a78600089898989898989612ccb565b611e0b60408051808201825260008082528251606081018452818152602081810183905293810191909152909182015290565b600d805483908110611e1f57611e1f615669565b60009182526020918290206040805180820182526002909302909101805463ffffffff9081168452825160608101845260019092015461ffff80821684526201000082041683870152600160201b900416918101919091529181019190915292915050565b60006114d9611e91611b9d565b6000906130c3565b604051633d99f84560e21b8152733d4f1ee041c31afc0fbda4f058d34544d71eb6ad9063f667e11490611828906000908a908a908a908a908a908a9060040161533c565b60606000601201805480602002602001604051908101604052809291908181526020018280548015611f3857602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311611f1a575b5050505050905090565b6040516316147f8760e31b815273ac6eefcc699047856c07c8679e1339903bd5ffcc9063b0a3fc38906115b6906000908990899089908990899060040161567f565b6040516309ea0cfb60e11b815260006004820181905290733d4f1ee041c31afc0fbda4f058d34544d71eb6ad906313d419f690602401611498565b604051636055f93560e01b8152733d4f1ee041c31afc0fbda4f058d34544d71eb6ad90636055f935906116be9060009086908690600401615274565b604051637b55bff360e01b815273ac6eefcc699047856c07c8679e1339903bd5ffcc90637b55bff3906113cf906000908b908b908b908b908b908b908b906004016156b2565b600061151886868686866000611408565b60405163179aac6b60e21b8152600060048201526024810182905273ac6eefcc699047856c07c8679e1339903bd5ffcc90635e6ab1ac90604401610f62565b604080516060808201835260008083526020808401829052838501829052845180840186528281528082018390528501829052868252600b81528482206001600160a01b0387168352600f01815290849020845192830185525460ff80821615158452610100820416918301919091526201000090046001600160601b03169281019290925290610df1565b6121c36040518061026001604052806000815260200160006001600160a01b03168152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160001515815260200160001515815260200160001515815260200160008152602001600081526020016060815260200160008152602001600081526020016000151581525090565b60405163ddb6398360e01b8152600060048201526024810183905273ac6eefcc699047856c07c8679e1339903bd5ffcc9063ddb6398390604401600060405180830381865af415801561221a573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610df491908101906157ad565b60405163370d357760e01b8152600060048201526024810182905273ac6eefcc699047856c07c8679e1339903bd5ffcc9063370d357790604401610f62565b6060833b6122e55760405162461bcd60e51b815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f6044820152651b9d1c9858dd60d21b60648201526084015b60405180910390fd5b600080856001600160a01b0316856040516123009190615905565b600060405180830381855af49150503d806000811461233b576040519150601f19603f3d011682016040523d82523d6000602084013e612340565b606091505b50915091506115188282866130d3565b6000818152600b8301602052604081206010810154820361237657600301549050610df4565b600c810154601082015460118301546123a192919061239c90889063ffffffff1661299c565b61310c565b949350505050565b6000806123b586612806565b600a87015490915060009061245c9088906001600160a01b031663782d6fe1336123e0600143615937565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401602060405180830381865afa158015612429573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061244d919061594a565b6001600160601b031684613188565b9050612467866131b6565b612471873361324d565b6008870154612481906001615973565b600888018190556000906124949061330a565b905060006124a6898385878c8b613373565b336000908152600c8b016020908152604080832063ffffffff87169055805192835290820190529091506124e89082906124e08c88612982565b8b8b8b61353a565b5063ffffffff16979650505050505050565b606080606080600086600b0160008781526020019081526020016000209050806005018160060182600701836008018380548060200260200160405190810160405280929190818152602001828054801561257e57602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311612560575b50505050509350828054806020026020016040519081016040528092919081815260200182805480156125d057602002820191906000526020600020905b8154815260200190600101908083116125bc575b5050505050925081805480602002602001604051908101604052809291908181526020016000905b828210156126a457838290600052602060002001805461261790615986565b80601f016020809104026020016040519081016040528092919081815260200182805461264390615986565b80156126905780601f1061266557610100808354040283529160200191612690565b820191906000526020600020905b81548152906001019060200180831161267357829003601f168201915b5050505050815260200190600101906125f8565b50505050915080805480602002602001604051908101604052809291908181526020016000905b828210156127775783829060005260206000200180546126ea90615986565b80601f016020809104026020016040519081016040528092919081815260200182805461271690615986565b80156127635780601f1061273857610100808354040283529160200191612763565b820191906000526020600020905b81548152906001019060200180831161274657829003601f168201915b5050505050815260200190600101906126cb565b50505050905094509450945094505092959194509250565b60008061279e868686866123a9565b6000818152600b880160205260409081902060138101805460ff191660011790559051919250907f9fb4e5204ac554428e5c744568b78732c229c76c0b5eaebdca7171c41366f6af906127f49084815260200190565b60405180910390a15095945050505050565b600081601001600c9054906101000a90046001600160a01b03166001600160a01b0316639b3c1e226040518163ffffffff1660e01b8152600401602060405180830381865afa15801561285d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061288191906151bc565b600a83015460098401546040516370a0823160e01b81526001600160a01b0391821660048201529116906370a0823190602401602060405180830381865afa1580156128d1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128f591906151bc565b83600a0160009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561294a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061296e91906151bc565b6129789190615937565b610df49190615937565b6000610df1612991844361299c565b5161ffff1683613614565b604080516060810182526000808252602082018190529181019190915260006129dd83604051806060016040528060408152602001615c376040913961362d565b600d8501549091506000819003612a34576040518060600160405280612a06876007015461365d565b61ffff168152602001612a1c876007015461365d565b61ffff16815260006020909101529250610df4915050565b63ffffffff8216600d8601612a4a600184615937565b81548110612a5a57612a5a615669565b600091825260209091206002909102015463ffffffff1611612aec57600d8501612a85600183615937565b81548110612a9557612a95615669565b6000918252602091829020604080516060810182526002939093029091016001015461ffff80821684526201000082041693830193909352600160201b90920463ffffffff16918101919091529250610df4915050565b8163ffffffff1685600d01600081548110612b0957612b09615669565b600091825260209091206002909102015463ffffffff161115612b3e576040518060600160405280612a06876007015461365d565b600080612b4c600184615937565b90505b81811115612c415760006002612b658484615937565b612b6f91906159c0565b612b799083615937565b9050600088600d018281548110612b9257612b92615669565b60009182526020918290206040805180820182526002909302909101805463ffffffff9081168452825160608101845260019092015461ffff80821684526201000082041683870152600160201b9004811692820192909252928201929092528051909250878216911603612c1257602001519550610df4945050505050565b805163ffffffff80881691161015612c2c57819350612c3a565b612c37600183615937565b92505b5050612b4f565b86600d018281548110612c5657612c56615669565b6000918252602091829020604080516060810182526002939093029091016001015461ffff80821684526201000082041693830193909352600160201b90920463ffffffff1691810191909152979650505050505050565b6000610df1612cbd844361299c565b6020015161ffff1683613614565b606087871015612d275760405162461bcd60e51b815260206004820152602160248201527f6c61737450726f706f73616c4964203e3d20666972737450726f706f73616c496044820152601960fa1b60648201526084016122dc565b6000612d338989615937565b612d3e906001615973565b90506000816001600160401b03811115612d5a57612d5a613c1e565b604051908082528060200260200182016040528015612de057816020015b612dcd60405180610120016040528060008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600063ffffffff168152602001606081525090565b815260200190600190039081612d785790505b509050600080612e03604051806040016040528060008152602001600081525090565b8c5b8c81116130b0578e600b01600082815260200190815260200160002093508a8015612e345750600e84015460ff165b6130a057600a84015482526011840154600160801b90046001600160401b031660208301528915612ed5576000612e7383600001518460200151613682565b9050804311612ed35760405162461bcd60e51b815260206004820152602660248201527f616c6c2070726f706f73616c73206d75737420626520646f6e65207769746820604482015265766f74696e6760d01b60648201526084016122dc565b505b600084600b015490506000856010015490506127108e61ffff1682612efa91906159e2565b612f0491906159c0565b821015612f125750506130a0565b60008a6001600160401b03811115612f2c57612f2c613c1e565b604051908082528060200260200182016040528015612f7157816020015b6040805180820190915260008082526020820152815260200190600190039081612f4a5790505b50905060005b8b81101561300b578760140160008e8e84818110612f9757612f97615669565b9050602002016020810190612fac91906151a1565b63ffffffff908116825260208083019390935260409182016000208251808401909352548082168352600160201b900416918101919091528251839083908110612ff857612ff8615669565b6020908102919091010152600101612f77565b5060408051610120810182528651815260208088015190820152908101849052600c8801546060820152600d880154608082015260a08101839052601188015463ffffffff600160201b91829004811660c08401528954919091041660e08201526101008101829052888761307f816159f9565b98508151811061309157613091615669565b60200260200101819052505050505b6130a9816159f9565b9050612e05565b50508252509a9950505050505050505050565b6000610df1836006015483613614565b606083156130e2575081611d19565b8251156130f25782518084602001fd5b8160405162461bcd60e51b81526004016122dc9190615a12565b6000808361311c866127106159e2565b61312691906159c0565b90506000620f424082856040015163ffffffff1661314491906159e2565b61314e91906159c0565b9050600081856000015161ffff166131669190615973565b9050600061317c866020015161ffff1683613698565b9050611a788188613614565b600061319484836130c3565b9050808311611d195760405163ead8241560e01b815260040160405180910390fd5b6020810151518151511415806131d3575060408101515181515114155b806131e5575060608101515181515114155b156132035760405163ccb0ce3f60e01b815260040160405180910390fd5b80515160000361322657604051630f24cd7360e01b815260040160405180910390fd5b805151600a101561324a576040516308e3b1eb60e11b815260040160405180910390fd5b50565b6001600160a01b0381166000908152600c83016020526040902054801561330557600061327a84836136a7565b9050600981600a811115613290576132906144f1565b14806132ad5750600181600a8111156132ab576132ab6144f1565b145b806132c95750600081600a8111156132c7576132c76144f1565b145b806132e55750600a81600a8111156132e3576132e36144f1565b145b15613303576040516306bee79560e01b815260040160405180910390fd5b505b505050565b600063ffffffff82111561336f5760405162461bcd60e51b815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203360448201526532206269747360d01b60648201526084016122dc565b5090565b6010860154600090819061339d9061339890600160401b900463ffffffff1643615973565b6138a0565b905060008860040154826001600160401b03166133ba9190615973565b905060008960050154826133ce9190615973565b63ffffffff808b166000818152600b8e01602090815260409091208054938a16600160201b0267ffffffffffffffff199094169092179290921781556001810180546001600160a01b03191633179055600281018b90558851805191975092935061343f9260058801920190613976565b50602080870151805161345892600688019201906139d7565b5060408601518051613474916007870191602090910190613a12565b5060608601518051613490916008870191602090910190613a64565b5060098401829055600a8401819055601084018790556134af4361330a565b60118501805463ffffffff191663ffffffff929092169190911790556134d44261330a565b6011850180546001600160401b03909516600160401b026fffffffffffffffff00000000000000001963ffffffff93909316600160201b02929092166fffffffffffffffffffffffff000000001990951694909417179092555090979650505050505050565b855483516020850151604080870151606088015160098c0154600a8d015493517f7d84a6263ae0d98d3329bd7b46bb4e8d6f98cd35a7adb45c274c8b7fd5ebd5e09761359d9763ffffffff90911696339691959094909390929091908c90615a25565b60405180910390a185546011870154600288015460405163ffffffff808616947fd9d12651716feaac10e3b79bd2960ad42ebfd84969b71a2e226ec99972a8712e946136049491909216928b926001600160401b03600160401b9091041691908b90615ac3565b60405180910390a2505050505050565b600061271061362384846159e2565b610df191906159c0565b60008163ffffffff8411156136555760405162461bcd60e51b81526004016122dc9190615a12565b509192915050565b600061ffff82111561336f5760405163555abf0160e11b815260040160405180910390fd5b60008183116136915781610df1565b5090919050565b60008183106136915781610df1565b600081836008015410156137095760405162461bcd60e51b8152602060048201526024808201527f4e6f756e7344414f3a3a73746174653a20696e76616c69642070726f706f73616044820152631b081a5960e21b60648201526084016122dc565b6000828152600b840160205260409020600e810154610100900460ff1615613735576008915050610df4565b600e81015460ff161561374c576002915050610df4565b6011810154600160401b90046001600160401b0316431161377157600a915050610df4565b80600901544311613786576000915050610df4565b80600a0154431161379b576001915050610df4565b6011810154600160801b90046001600160401b031643116137c0576009915050610df4565b6137ca8482613908565b156137d9576003915050610df4565b80600401546000036137ef576004915050610df4565b600e81015462010000900460ff161561380c576007915050610df4565b613816848261393e565b6001600160a01b031663c1a287e26040518163ffffffff1660e01b8152600401602060405180830381865afa158015613853573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061387791906151bc565b81600401546138869190615973565b4210613896576006915050610df4565b6005915050610df4565b60006001600160401b0382111561336f5760405162461bcd60e51b815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203660448201526534206269747360d01b60648201526084016122dc565b600b810154600c82015460009190811115806123a15750825461393690859063ffffffff9081169061235016565b119392505050565b601381015460009060ff1615613962575060188201546001600160a01b0316610df4565b5060098201546001600160a01b0316610df4565b8280548282559060005260206000209081019282156139cb579160200282015b828111156139cb57825182546001600160a01b0319166001600160a01b03909116178255602090920191600190910190613996565b5061336f929150613ab6565b8280548282559060005260206000209081019282156139cb579160200282015b828111156139cb5782518255916020019190600101906139f7565b828054828255906000526020600020908101928215613a58579160200282015b82811115613a585782518290613a489082615b50565b5091602001919060010190613a32565b5061336f929150613acb565b828054828255906000526020600020908101928215613aaa579160200282015b82811115613aaa5782518290613a9a9082615b50565b5091602001919060010190613a84565b5061336f929150613ae8565b5b8082111561336f5760008155600101613ab7565b8082111561336f576000613adf8282613b05565b50600101613acb565b8082111561336f576000613afc8282613b05565b50600101613ae8565b508054613b1190615986565b6000825580601f10613b21575050565b601f01602090049060005260206000209081019061324a9190613ab6565b600060208284031215613b5157600080fd5b5035919050565b815181526020808301516101e0830191613b7c908401826001600160a01b03169052565b5060408301516040830152606083015160608301526080830151608083015260a083015160a083015260c083015160c083015260e083015160e083015261010080840151818401525061012080840151818401525061014080840151613be58285018215159052565b505061016083810151151590830152610180808401511515908301526101a080840151908301526101c092830151929091019190915290565b634e487b7160e01b600052604160045260246000fd5b604051606081016001600160401b0381118282101715613c5657613c56613c1e565b60405290565b6040516101e081016001600160401b0381118282101715613c5657613c56613c1e565b60405161026081016001600160401b0381118282101715613c5657613c56613c1e565b604051601f8201601f191681016001600160401b0381118282101715613cca57613cca613c1e565b604052919050565b60006001600160401b03821115613ceb57613ceb613c1e565b5060051b60200190565b600082601f830112613d0657600080fd5b81356001600160401b03811115613d1f57613d1f613c1e565b613d32601f8201601f1916602001613ca2565b818152846020838601011115613d4757600080fd5b816020850160208301376000918101602001919091529392505050565b6001600160a01b038116811461324a57600080fd5b600082601f830112613d8a57600080fd5b81356020613d9f613d9a83613cd2565b613ca2565b82815260059290921b84018101918181019086841115613dbe57600080fd5b8286015b84811015613e505780356001600160401b0380821115613de25760008081fd5b908801906060828b03601f1901811315613dfc5760008081fd5b613e04613c34565b8784013583811115613e165760008081fd5b613e248d8a83880101613cf5565b8252506040925082840135613e3881613d64565b81890152920135908201528352918301918301613dc2565b509695505050505050565b600082601f830112613e6c57600080fd5b81356020613e7c613d9a83613cd2565b8083825260208201915060208460051b870101935086841115613e9e57600080fd5b602086015b84811015613e50578035613eb681613d64565b8352918301918301613ea3565b600082601f830112613ed457600080fd5b81356020613ee4613d9a83613cd2565b8083825260208201915060208460051b870101935086841115613f0657600080fd5b602086015b84811015613e505780358352918301918301613f0b565b600082601f830112613f3357600080fd5b81356020613f43613d9a83613cd2565b82815260059290921b84018101918181019086841115613f6257600080fd5b8286015b84811015613e505780356001600160401b03811115613f855760008081fd5b613f938986838b0101613cf5565b845250918301918301613f66565b60008060008060008060c08789031215613fba57600080fd5b86356001600160401b0380821115613fd157600080fd5b613fdd8a838b01613d79565b97506020890135915080821115613ff357600080fd5b613fff8a838b01613e5b565b9650604089013591508082111561401557600080fd5b6140218a838b01613ec3565b9550606089013591508082111561403757600080fd5b6140438a838b01613f22565b9450608089013591508082111561405957600080fd5b6140658a838b01613f22565b935060a089013591508082111561407b57600080fd5b5061408889828a01613cf5565b9150509295509295509295565b6000602082840312156140a757600080fd5b8135611d1981613d64565b60008060008060008060008789036101c08112156140cf57600080fd5b88356140da81613d64565b975060208901356140ea81613d64565b965060408901356140fa81613d64565b9550606089013561410a81613d64565b9450608089013561411a81613d64565b935060c0609f198201121561412e57600080fd5b60a089019250606061015f198201121561414757600080fd5b506101608801905092959891949750929550565b803563ffffffff8116811461416f57600080fd5b919050565b60008060008060008060c0878903121561418d57600080fd5b86356001600160401b03808211156141a457600080fd5b6141b08a838b01613e5b565b975060208901359150808211156141c657600080fd5b6141d28a838b01613ec3565b965060408901359150808211156141e857600080fd5b6141f48a838b01613f22565b9550606089013591508082111561420a57600080fd5b6142168a838b01613f22565b9450608089013591508082111561422c57600080fd5b5061423989828a01613cf5565b92505061424860a0880161415b565b90509295509295509295565b60008151808452602080850194506020840160005b8381101561428e5781516001600160a01b031687529582019590820190600101614269565b509495945050505050565b60008151808452602080850194506020840160005b8381101561428e578151875295820195908201906001016142ae565b60005b838110156142e55781810151838201526020016142cd565b50506000910152565b600081518084526143068160208601602086016142ca565b601f01601f19169290920160200192915050565b60008282518085526020808601955060208260051b8401016020860160005b8481101561436757601f198684030189526143558383516142ee565b98840198925090830190600101614339565b5090979650505050505050565b6080815260006143876080830187614254565b82810360208401526143998187614299565b905082810360408401526143ad818661431a565b90508281036060840152610f1c818561431a565b600080600080600060a086880312156143d957600080fd5b85356001600160401b03808211156143f057600080fd5b6143fc89838a01613e5b565b9650602088013591508082111561441257600080fd5b61441e89838a01613ec3565b9550604088013591508082111561443457600080fd5b61444089838a01613f22565b9450606088013591508082111561445657600080fd5b61446289838a01613f22565b9350608088013591508082111561447857600080fd5b5061448588828901613cf5565b9150509295509295909350565b803560ff8116811461416f57600080fd5b600080600080600060a086880312156144bb57600080fd5b853594506144cb60208701614492565b93506144d960408701614492565b94979396509394606081013594506080013592915050565b634e487b7160e01b600052602160045260246000fd5b60208101600b831061452957634e487b7160e01b600052602160045260246000fd5b91905290565b60008083601f84011261454157600080fd5b5081356001600160401b0381111561455857600080fd5b60208301915083602082850101111561457057600080fd5b9250929050565b6000806020838503121561458a57600080fd5b82356001600160401b038111156145a057600080fd5b6145ac8582860161452f565b90969095509350505050565b600080604083850312156145cb57600080fd5b823591506145db60208401614492565b90509250929050565b815161ffff90811682526020808401519091169082015260408083015163ffffffff169082015260608101610df4565b60008083601f84011261462657600080fd5b5081356001600160401b0381111561463d57600080fd5b6020830191508360208260051b850101111561457057600080fd5b6000806020838503121561466b57600080fd5b82356001600160401b0381111561468157600080fd5b6145ac85828601614614565b60008060008060008060c087890312156146a657600080fd5b8635955060208701356001600160401b0380821115613ff357600080fd5b6000806000604084860312156146d957600080fd5b83356001600160401b038111156146ef57600080fd5b6146fb86828701614614565b909450925050602084013561470f81613d64565b809150509250925092565b6000806000806000806060878903121561473357600080fd5b86356001600160401b038082111561474a57600080fd5b6147568a838b01614614565b9098509650602089013591508082111561476f57600080fd5b61477b8a838b01614614565b9096509450604089013591508082111561479457600080fd5b506147a189828a0161452f565b979a9699509497509295939492505050565b600080600080606085870312156147c957600080fd5b843593506147d960208601614492565b925060408501356001600160401b038111156147f457600080fd5b6148008782880161452f565b95989497509550505050565b600080600080600080600060e0888a03121561482757600080fd5b87356001600160401b038082111561483e57600080fd5b61484a8b838c01613d79565b985060208a013591508082111561486057600080fd5b61486c8b838c01613e5b565b975060408a013591508082111561488257600080fd5b61488e8b838c01613ec3565b965060608a01359150808211156148a457600080fd5b6148b08b838c01613f22565b955060808a01359150808211156148c657600080fd5b6148d28b838c01613f22565b945060a08a01359150808211156148e857600080fd5b506148f58a828b01613cf5565b92505061490460c0890161415b565b905092959891949750929550565b60008060008060006080868803121561492a57600080fd5b8535945061493a60208701614492565b935060408601356001600160401b0381111561495557600080fd5b6149618882890161452f565b909450925061497490506060870161415b565b90509295509295909350565b60008060006060848603121561499557600080fd5b833592506149a560208501614492565b91506149b36040850161415b565b90509250925092565b600080600080600080600080610100898b0312156149d957600080fd5b8835975060208901356001600160401b03808211156149f757600080fd5b614a038c838d01613d79565b985060408b0135915080821115614a1957600080fd5b614a258c838d01613e5b565b975060608b0135915080821115614a3b57600080fd5b614a478c838d01613ec3565b965060808b0135915080821115614a5d57600080fd5b614a698c838d01613f22565b955060a08b0135915080821115614a7f57600080fd5b614a8b8c838d01613f22565b945060c08b0135915080821115614aa157600080fd5b614aad8c838d01613cf5565b935060e08b0135915080821115614ac357600080fd5b50614ad08b828c01613cf5565b9150509295985092959890939650565b803561ffff8116811461416f57600080fd5b600080600083850360a0811215614b0857600080fd5b84359350602085013592506060603f1982011215614b2557600080fd5b50614b2e613c34565b614b3a60408601614ae0565b8152614b4860608601614ae0565b6020820152614b596080860161415b565b6040820152809150509250925092565b63ffffffff81511682526020810151613305602084018261ffff8082511683528060208301511660208401525063ffffffff60408201511660408301525050565b6020808252825182820181905260009190848201906040850190845b81811015614bec57614bd9838551614b69565b9284019260809290920191600101614bc6565b50909695505050505050565b801515811461324a57600080fd5b600080600080600080600060c0888a031215614c2157600080fd5b8735965060208801359550614c3860408901614ae0565b94506060880135614c4881614bf8565b93506080880135614c5881614bf8565b925060a08801356001600160401b03811115614c7357600080fd5b614c7f8a828b01614614565b989b979a50959850939692959293505050565b60008151808452602080850194506020840160005b8381101561428e578151805163ffffffff908116895290840151168388015260409096019590820190600101614ca7565b600060208083018184528085518083526040925060408601915060408160051b87010184880160005b83811015614d9157888303603f1901855281518051845287810151888501528681015187850152606080820151908501526080808201519085015260a0808201519085015260c0808201519085015260e08082015163ffffffff16908501526101009081015161012091850182905290614d7d81860183614c92565b968901969450505090860190600101614d01565b509098975050505050505050565b60808101610df48284614b69565b602081526000610df16020830184614254565b600080600080600060608688031215614dd857600080fd5b8535945060208601356001600160401b0380821115614df657600080fd5b614e0289838a0161452f565b90965094506040880135915080821115614e1b57600080fd5b50614e288882890161452f565b969995985093965092949392505050565b600080600080600080600060e0888a031215614e5457600080fd5b8735965060208801356001600160401b0380821115614e7257600080fd5b614e7e8b838c01613e5b565b975060408a0135915080821115614e9457600080fd5b614ea08b838c01613ec3565b965060608a0135915080821115614eb657600080fd5b614ec28b838c01613f22565b955060808a0135915080821115614ed857600080fd5b614ee48b838c01613f22565b945060a08a0135915080821115614efa57600080fd5b614f068b838c01613cf5565b935060c08a0135915080821115614f1c57600080fd5b50614f298a828b01613cf5565b91505092959891949750929550565b60008060408385031215614f4b57600080fd5b823591506020830135614f5d81613d64565b809150509250929050565b602081528151602082015260006020830151614f8f60408401826001600160a01b03169052565b506040830151606083015260608301516080830152608083015160a083015260a083015160c083015260c083015160e083015260e08301516101008181850152808501519150506101208181850152808501519150506101408181850152808501519150506101606150048185018315159052565b84015190506101806150198482018315159052565b84015190506101a061502e8482018315159052565b8401516101c0848101919091528401516101e08085019190915284015161026061020080860182905291925090615069610280860184614254565b9086015161022086810191909152860151610240808701919091529095015115159301929092525090919050565b805161416f81613d64565b805161416f81614bf8565b60006101e082840312156150c057600080fd5b6150c8613c5c565b825181526150d860208401615097565b602082015260408301516040820152606083015160608201526080830151608082015260a083015160a082015260c083015160c082015260e083015160e082015261010080840151818301525061012080840151818301525061014061513f8185016150a2565b908201526101606151518482016150a2565b908201526101806151638482016150a2565b908201526101a083810151908201526101c0928301519281019290925250919050565b60006020828403121561519857600080fd5b610df182614ae0565b6000602082840312156151b357600080fd5b610df18261415b565b6000602082840312156151ce57600080fd5b5051919050565b6000602082840312156151e757600080fd5b8151600b8110611d1957600080fd5b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b8381526040602082015260006152396040830184866151f6565b95945050505050565b81835260006001600160fb1b0383111561525b57600080fd5b8260051b80836020870137939093016020019392505050565b838152604060208201526000615239604083018486615242565b87815286602082015260e0604082015260006152ad60e0830188614254565b82810360608401526152bf8188614299565b905082810360808401526152d3818761431a565b905082810360a08401526152e7818661431a565b905082810360c08401526152fb81856142ee565b9a9950505050505050505050565b848152606060208201526000615323606083018587615242565b905060018060a01b038316604083015295945050505050565b87815260806020820152600061535660808301888a615242565b8281036040840152615369818789615242565b905082810360608401526152fb8185876151f6565b86815285602082015260ff8516604082015260a0606082015260006153a760a0830185876151f6565b905063ffffffff83166080830152979650505050505050565b600082825180855260208086019550808260051b84010181860160005b8481101561436757601f19868403018952815160608151818652615403828701826142ee565b838801516001600160a01b0316878901526040938401519390960192909252505097830197908301906001016153dd565b60008282518085526020808601955060208260051b8401016020860160005b8481101561436757601f1986840301895261546f8383516142ee565b98840198925090830190600101615453565b8051608080845281519084018190526000916020919082019060a0860190845b818110156154c65783516001600160a01b0316835292840192918401916001016154a1565b50506020850151925085810360208701526154e18184614299565b92505050604083015184820360408601526154fc8282615434565b915050606083015184820360608601526152398282615434565b85815260a06020820152600061552f60a08301876153c0565b82810360408401526155418187615481565b9050828103606084015261555581866142ee565b91505063ffffffff831660808301529695505050505050565b6000806040838503121561558157600080fd5b825161558c81613d64565b6020840151909250614f5d81613d64565b85815284602082015260ff84166040820152608060608201526000610f1c6080830184866151f6565b86815285602082015260c0604082015260006155e560c08301876153c0565b82810360608401526155f78187615481565b9050828103608084015261560b81866142ee565b905082810360a084015261561f81856142ee565b9998505050505050505050565b8381526020808201849052825161ffff9081166040808501919091529184015116606083015282015163ffffffff16608082015260a081016123a1565b634e487b7160e01b600052603260045260246000fd5b86815285602082015260806040820152600061569f6080830186886151f6565b828103606084015261561f8185876151f6565b60006101008a83528960208401528060408401526156d28184018a614254565b905082810360608401526156e68189614299565b905082810360808401526156fa818861431a565b905082810360a084015261570e818761431a565b905082810360c084015261572281866142ee565b905082810360e084015261573681856142ee565b9b9a5050505050505050505050565b600082601f83011261575657600080fd5b81516020615766613d9a83613cd2565b8083825260208201915060208460051b87010193508684111561578857600080fd5b602086015b84811015613e505780516157a081613d64565b835291830191830161578d565b6000602082840312156157bf57600080fd5b81516001600160401b03808211156157d657600080fd5b9083019061026082860312156157eb57600080fd5b6157f3613c7f565b8251815261580360208401615097565b602082015260408301516040820152606083015160608201526080830151608082015260a083015160a082015260c083015160c082015260e083015160e082015261010080840151818301525061012080840151818301525061014061586a8185016150a2565b9082015261016061587c8482016150a2565b9082015261018061588e8482016150a2565b908201526101a083810151908201526101c080840151908201526101e080840151838111156158bc57600080fd5b6158c888828701615745565b91830191909152506102008381015190820152610220808401519082015261024091506158f68284016150a2565b91810191909152949350505050565b600082516159178184602087016142ca565b9190910192915050565b634e487b7160e01b600052601160045260246000fd5b81810381811115610df457610df4615921565b60006020828403121561595c57600080fd5b81516001600160601b0381168114611d1957600080fd5b80820180821115610df457610df4615921565b600181811c9082168061599a57607f821691505b6020821081036159ba57634e487b7160e01b600052602260045260246000fd5b50919050565b6000826159dd57634e487b7160e01b600052601260045260246000fd5b500490565b8082028115828204841417610df457610df4615921565b600060018201615a0b57615a0b615921565b5060010190565b602081526000610df160208301846142ee565b63ffffffff8a1681526001600160a01b038916602082015261012060408201819052600090615a568382018b614254565b90508281036060840152615a6a818a614299565b90508281036080840152615a7e818961431a565b905082810360a0840152615a92818861431a565b90508560c08401528460e0840152828103610100840152615ab381856142ee565b9c9b505050505050505050505050565b63ffffffff8616815260a060208201526000615ae260a0830187614254565b6001600160401b0395909516604083015250606081019290925260809091015292915050565b601f821115613305576000816000526020600020601f850160051c81016020861015615b315750805b601f850160051c820191505b818110156116ea57828155600101615b3d565b81516001600160401b03811115615b6957615b69613c1e565b615b7d81615b778454615986565b84615b08565b602080601f831160018114615bb25760008415615b9a5750858301515b600019600386901b1c1916600185901b1785556116ea565b600085815260208120601f198616915b82811015615be157888601518255948401946001909101908401615bc2565b5085821015615bff5787850151600019600388901b60f8161c191681555b5050505050600190811b0190555056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c65644e6f756e7344414f3a3a67657444796e616d696351756f72756d506172616d7341743a20626c6f636b206e756d62657220657863656564732033322062697473a26469706673582212209727ca74986184ed031177b5021a46512e6f96c4c604da0c453d87c2106b183b64736f6c63430008170033", + "nonce": "0x8", + "chainId": "0x1", + "accessList": null, + "type": null + }, + "additionalContracts": [], + "isFixedGasLimit": false + } + ], + "receipts": [ + { + "status": "0x1", + "cumulativeGasUsed": "0x9b6fd2", + "logs": [], + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "type": "0x2", + "transactionHash": "0xf5bbdf994c5c451133efb990bcde2544003a5bdd3c924877db95a14b97ab0982", + "transactionIndex": "0x74", + "blockHash": "0x2fb5db1009d76ea4039687fe481e262087e33cd13023aed87dc5da80c1af47a3", + "blockNumber": "0x12cdc66", + "gasUsed": "0x1e623e", + "effectiveGasPrice": "0x2180d294f", + "from": "0x918895f466eb3cd5fb181626f8e1b2fd8a9d5192", + "to": null, + "contractAddress": "0xd7c7c3c447df757a77c81fcff07f10bb22d98f4a" + }, + { + "status": "0x1", + "cumulativeGasUsed": "0x9e5709", + "logs": [], + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "type": "0x2", + "transactionHash": "0x89857e7b83a9aa57ade9d740ec6de5e57302eb3510327110e00e0b3b18622589", + "transactionIndex": "0x75", + "blockHash": "0x2fb5db1009d76ea4039687fe481e262087e33cd13023aed87dc5da80c1af47a3", + "blockNumber": "0x12cdc66", + "gasUsed": "0x2e737", + "effectiveGasPrice": "0x2180d294f", + "from": "0x918895f466eb3cd5fb181626f8e1b2fd8a9d5192", + "to": null, + "contractAddress": "0xb5aa61eff82ea7b4ea6443532df15b7d4b40c3a0" + }, + { + "status": "0x1", + "cumulativeGasUsed": "0xaf41c2", + "logs": [], + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "type": "0x2", + "transactionHash": "0x8f40d8b469c009bde3cb810314babc483ea3e47073180ac4e43917424325f7da", + "transactionIndex": "0x76", + "blockHash": "0x2fb5db1009d76ea4039687fe481e262087e33cd13023aed87dc5da80c1af47a3", + "blockNumber": "0x12cdc66", + "gasUsed": "0x10eab9", + "effectiveGasPrice": "0x2180d294f", + "from": "0x918895f466eb3cd5fb181626f8e1b2fd8a9d5192", + "to": null, + "contractAddress": "0x3d4f1ee041c31afc0fbda4f058d34544d71eb6ad" + }, + { + "status": "0x1", + "cumulativeGasUsed": "0xeccc07", + "logs": [], + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "type": "0x2", + "transactionHash": "0xa603f6aebe14018d59b50528a7c8fa404c310e7a23e016e114a33fadfe838f2a", + "transactionIndex": "0x77", + "blockHash": "0x2fb5db1009d76ea4039687fe481e262087e33cd13023aed87dc5da80c1af47a3", + "blockNumber": "0x12cdc66", + "gasUsed": "0x3d8a45", + "effectiveGasPrice": "0x2180d294f", + "from": "0x918895f466eb3cd5fb181626f8e1b2fd8a9d5192", + "to": null, + "contractAddress": "0xac6eefcc699047856c07c8679e1339903bd5ffcc" + }, + { + "status": "0x1", + "cumulativeGasUsed": "0x103b661", + "logs": [], + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "type": "0x2", + "transactionHash": "0x3234f140996918456dfdfee0ed2e8081f9b971a9c004b24b29cc4d9aa7a96e40", + "transactionIndex": "0x78", + "blockHash": "0x2fb5db1009d76ea4039687fe481e262087e33cd13023aed87dc5da80c1af47a3", + "blockNumber": "0x12cdc66", + "gasUsed": "0x16ea5a", + "effectiveGasPrice": "0x2180d294f", + "from": "0x918895f466eb3cd5fb181626f8e1b2fd8a9d5192", + "to": null, + "contractAddress": "0x3e4e4d094a73aac69ff6592cda602b76134951d6" + }, + { + "status": "0x1", + "cumulativeGasUsed": "0x152b42d", + "logs": [], + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "type": "0x2", + "transactionHash": "0x7c7453c2143ccf8e68988aa6bfd0bf9f8c6eee1ba6c193090e466af34f669428", + "transactionIndex": "0x79", + "blockHash": "0x2fb5db1009d76ea4039687fe481e262087e33cd13023aed87dc5da80c1af47a3", + "blockNumber": "0x12cdc66", + "gasUsed": "0x4efdcc", + "effectiveGasPrice": "0x2180d294f", + "from": "0x918895f466eb3cd5fb181626f8e1b2fd8a9d5192", + "to": null, + "contractAddress": "0xa23e8a919d29d74ee24d909d80f4bc8778d656d1" + } + ], + "libraries": [ + "contracts/governance/NounsDAOAdmin.sol:NounsDAOAdmin:0xd7c7c3c447Df757a77C81FcFf07f10bB22d98f4a", + "contracts/governance/NounsDAODynamicQuorum.sol:NounsDAODynamicQuorum:0xB5Aa61EfF82Ea7B4ea6443532dF15B7d4B40C3A0", + "contracts/governance/NounsDAOProposals.sol:NounsDAOProposals:0xac6eefcC699047856c07c8679e1339903bd5ffCC", + "contracts/governance/NounsDAOVotes.sol:NounsDAOVotes:0x3e4e4D094a73AAC69Ff6592CDa602B76134951d6", + "contracts/governance/fork/NounsDAOFork.sol:NounsDAOFork:0x3d4F1EE041C31aFc0FBda4f058D34544d71EB6aD" + ], + "pending": [], + "returns": { + "daoLogic": { + "internal_type": "contract NounsDAOLogicV4", + "value": "0xA23e8A919D29d74Ee24d909D80f4bC8778d656d1" + } + }, + "timestamp": 1713864921, + "chain": 1, + "commit": "82b8d911" +} \ No newline at end of file diff --git a/packages/nouns-contracts/broadcast/DeployDAOLogicOptimized.s.sol/1/run-latest.json b/packages/nouns-contracts/broadcast/DeployDAOLogicOptimized.s.sol/1/run-latest.json new file mode 100644 index 0000000000..992fb5ec0a --- /dev/null +++ b/packages/nouns-contracts/broadcast/DeployDAOLogicOptimized.s.sol/1/run-latest.json @@ -0,0 +1,245 @@ +{ + "transactions": [ + { + "hash": "0xf5bbdf994c5c451133efb990bcde2544003a5bdd3c924877db95a14b97ab0982", + "transactionType": "CREATE", + "contractName": "NounsDAOAdmin", + "contractAddress": "0xd7c7c3c447df757a77c81fcff07f10bb22d98f4a", + "function": null, + "arguments": null, + "transaction": { + "from": "0x918895f466eb3cd5fb181626f8e1b2fd8a9d5192", + "to": null, + "gas": "0x277cd7", + "value": null, + "input": "0x61230c61003a600b82828239805160001a60731461002d57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600436106102315760003560e01c8063a267a3d11161013a578063db725e17116100c2578063e9c714f211610086578063e9c714f21461052f578063ec91deda14610544578063ee186559146104a2578063f5f4714c14610564578063fd22b60a146104dc57600080fd5b8063db725e17146104d3578063dfcda1ef146104dc578063e2560772146104e6578063e5eb5abf14610506578063e7951bb91461052657600080fd5b8063c10eb14d11610109578063c10eb14d14610478578063c82fbd0814610371578063cbff4a13146104a2578063ccfa51c9146104ab578063d3f662e1146104b357600080fd5b8063a267a3d114610419578063a78b5f1a14610423578063b71d1a0c14610443578063bf7a29631461046357600080fd5b80632df01bdb116101bd57806374b157b81161018c57806374b157b8146103795780637a3da69114610399578063842e4dae146103b95780639547aecb146103d957806397d048e5146103f957600080fd5b80632df01bdb1461031157806344697f981461033157806350196db31461035157806351e313e01461037157600080fd5b80631e7b5d3a116102045780631e7b5d3a146102ad57806326e6dcb0146102c957806327126e67146102d25780632b5ca189146102dc5780632cfc81c6146102fc57600080fd5b806306ef9d36146102365780630dc0ce3f146102585780630ea2d98c1461026d5780631dfb1b5a1461028d575b600080fd5b81801561024257600080fd5b50610256610251366004611ef2565b610584565b005b81801561026457600080fd5b506102566105f2565b81801561027957600080fd5b50610256610288366004611ef2565b610624565b81801561029957600080fd5b506102566102a8366004611ef2565b610715565b6102b66103e881565b6040519081526020015b60405180910390f35b6102b661177081565b6102b66212750081565b8180156102e857600080fd5b506102566102f7366004611f24565b6107f6565b81801561030857600080fd5b50610256610891565b81801561031d57600080fd5b5061025661032c366004611f5d565b610986565b81801561033d57600080fd5b5061025661034c366004611f78565b610a2c565b81801561035d57600080fd5b5061025661036c366004611fcd565b610ad3565b6102b6600181565b81801561038557600080fd5b50610256610394366004611f24565b610c67565b8180156103a557600080fd5b506102566103b4366004611fcd565b610d28565b8180156103c557600080fd5b506102566103d4366004611ef2565b610ecc565b8180156103e557600080fd5b506102566103f4366004612034565b610f82565b81801561040557600080fd5b50610256610414366004611ef2565b610fb8565b6102b66202a30081565b81801561042f57600080fd5b5061025661043e3660046120a7565b6110a6565b81801561044f57600080fd5b5061025661045e366004611f5d565b611129565b81801561046f57600080fd5b506102566111a7565b81801561048457600080fd5b5061048d611262565b604080519283529015156020830152016102c0565b6102b661c4e081565b6102b660c881565b8180156104bf57600080fd5b506102566104ce366004611f5d565b611320565b6102b6611c2081565b6102b6620189c081565b8180156104f257600080fd5b50610256610501366004611f24565b6113b7565b81801561051257600080fd5b50610256610521366004611f24565b611436565b6102b66107d081565b81801561053b57600080fd5b506102566114ef565b81801561055057600080fd5b5061025661055f3660046120e9565b611605565b81801561057057600080fd5b5061025661057f366004611f5d565b6117de565b6000546001600160a01b031633146105af57604051633057182d60e21b815260040160405180910390fd5b7f8008239436e26bac1476fd338f5a2ec6415794efc1afa04145a4845547f37adc60006017015460408051918252602082018490520160405180910390a1601755565b6000546001600160a01b0316331461061d57604051633057182d60e21b815260040160405180910390fd5b6000601955565b6000546001600160a01b0316331461064f57604051633057182d60e21b815260040160405180910390fd5b611c2081101580156106645750620189c08111155b6106cf5760405162461bcd60e51b815260206004820152603160248201527f4e6f756e7344414f3a3a5f736574566f74696e67506572696f643a20696e76616044820152701b1a59081d9bdd1a5b99c81c195c9a5bd9607a1b60648201526084015b60405180910390fd5b600580549082905560408051828152602081018490527f7e3f7f0708a84de9203036abaa450dccc85ad5ff52f78c170f3edb55cf5e882891015b60405180910390a15050565b6000546001600160a01b0316331461074057604051633057182d60e21b815260040160405180910390fd5b600181101580156107545750620189c08111155b6107b85760405162461bcd60e51b815260206004820152602f60248201527f4e6f756e7344414f3a3a5f736574566f74696e6744656c61793a20696e76616c60448201526e696420766f74696e672064656c617960881b60648201526084016106c6565b600480549082905560408051828152602081018490527fc565b045403dc03c2eea82b81a0465edad9e2e7fc4d97e11421c209da93d7a939101610709565b6000546001600160a01b0316331461082157604051633057182d60e21b815260040160405180910390fd5b600061082f43825b9061185c565b60408101805163ffffffff851690915290915061084b82611b73565b6040805163ffffffff8084168252851660208201527f5e3adb1066359dafa23c629f245d93543856115700821dcb4debc416f393c46991015b60405180910390a1505050565b6000600e01546001600160a01b031633146108bf57604051631bd9bb1b60e31b815260040160405180910390fd5b600354600e546040517fc5644f3588a066b15dcf6b636b74aadca57cfaccf608d9de7d8786364b7a8d0292610902926001600160a01b0391821692911690612123565b60405180910390a1600e546001600160a01b031660005b60030180546001600160a01b0319166001600160a01b03928316179055600e546040517f7ad92e57a52c4e3e83ba624622b14e3a5efa0160dd6f9a7975c43ea66bad79ea9261096c921690600090612123565b60405180910390a1600e80546001600160a01b0319169055565b6000546001600160a01b031633146109b157604051633057182d60e21b815260040160405180910390fd5b7ff890a07a97cb2de686a62235272191a50a2113c4fda17ce6ab5ffd20a06d56d36000601001546040516109f791600160601b90046001600160a01b0316908490612123565b60405180910390a1601080546001600160a01b03909216600160601b026bffffffffffffffffffffffff909216919091179055565b6000546001600160a01b03163314610a5757604051633057182d60e21b815260040160405180910390fd5b600980546001600160a01b038086166001600160a01b0319928316811790935560188054868316908416811790915560008054928616929093168217909255604080519384526020840192909252908201527f13c01549e11ee7e3b2c89b08a2fd55875d85aaf1aa217bf18d1ab0f88f959d2490606001610884565b6000546001600160a01b03163314610afe57604051633057182d60e21b815260040160405180910390fd5b6000610b0a4382610829565b90506117708261ffff161115610b885760405162461bcd60e51b815260206004820152603d60248201527f4e6f756e7344414f3a3a5f7365744d617851756f72756d566f7465734250533a60448201527f20696e76616c6964206d61782071756f72756d20766f7465732062707300000060648201526084016106c6565b805161ffff80841691161115610c155760405162461bcd60e51b815260206004820152604660248201527f4e6f756e7344414f3a3a5f7365744d617851756f72756d566f7465734250533a60448201527f206d696e2071756f72756d20766f7465732062707320677265617465722074686064820152650c2dc40dac2f60d31b608482015260a4016106c6565b60208101805161ffff8416909152610c2c82611b73565b6040805161ffff8084168252851660208201527f4bfb1235074b38f02e5cf8ba90f535905417c196a12654f65ee0584512d706429101610884565b6000546001600160a01b03163314610c9257604051633057182d60e21b815260040160405180910390fd5b61c4e08163ffffffff161115610cbb576040516388a79ca760e01b815260040160405180910390fd5b6010805463ffffffff838116680100000000000000008181026bffffffff0000000000000000198516179094556040805194909304919091168084526020840191909152917fd185da00ceb738d5e65ef6936975bcb81fe742adc63d901592003d7bc22f4dfa9101610709565b6000546001600160a01b03163314610d5357604051633057182d60e21b815260040160405180910390fd5b6000610d5f4382610829565b905060c88261ffff1610158015610d7c57506107d08261ffff1611155b610dee5760405162461bcd60e51b815260206004820152603d60248201527f4e6f756e7344414f3a3a5f7365744d696e51756f72756d566f7465734250533a60448201527f20696e76616c6964206d696e2071756f72756d20766f7465732062707300000060648201526084016106c6565b806020015161ffff168261ffff161115610e7f5760405162461bcd60e51b815260206004820152604660248201527f4e6f756e7344414f3a3a5f7365744d696e51756f72756d566f7465734250533a60448201527f206d696e2071756f72756d20766f7465732062707320677265617465722074686064820152650c2dc40dac2f60d31b608482015260a4016106c6565b805161ffff83168252610e9182611b73565b6040805161ffff8084168252851660208201527ffaeebe30d875e399189096ea49fea81bd41fe6dfc86ad3550639063219e607789101610884565b6000546001600160a01b03163314610ef757604051633057182d60e21b815260040160405180910390fd5b62127500811115610f1b57604051637762590b60e01b815260040160405180910390fd5b6202a300811015610f3f57604051633430477560e11b815260040160405180910390fd5b7ffa0345f15af4cde74f214a8800528bd12cb260c12d8669007af35d869cb6877360006016015460408051918252602082018490520160405180910390a1601655565b610f8b86610986565b610f94856117de565b610f9e84846110a6565b610fa782610ecc565b610fb081610584565b505050505050565b6000546001600160a01b03163314610fe357604051633057182d60e21b815260040160405180910390fd5b60018110158015610ff657506103e88111155b6110685760405162461bcd60e51b815260206004820152603f60248201527f4e6f756e7344414f3a3a5f73657450726f706f73616c5468726573686f6c643a60448201527f20696e76616c69642070726f706f73616c207468726573686f6c64206270730060648201526084016106c6565b600680549082905560408051828152602081018490527ffc216faa269bf440fb06aa490693f409461bde9cdcb949c7b9f2cb79589e7a589101610709565b6000546001600160a01b031633146110d157604051633057182d60e21b815260040160405180910390fd5b6110db8282611d61565b6040517f6158953ac4c84a0a8642793ade32098d1ecd12702db9ce2eb7c72c4463a8fb0790611110906012908590859061213d565b60405180910390a161112460128383611e83565b505050565b6000546001600160a01b0316331461115457604051633057182d60e21b815260040160405180910390fd5b600180546001600160a01b038381166001600160a01b03198316179092556040519116907fca4f2f25d0898edd99413412fb94012f9e54ec8142f9b093e7720646a95b16a9906107099083908590612123565b6000600301546001600160a01b031633146112125760405162461bcd60e51b815260206004820152602560248201527f4e6f756e7344414f3a3a5f6275726e5665746f506f7765723a207665746f6572604482015264206f6e6c7960d81b60648201526084016106c6565b7fc5644f3588a066b15dcf6b636b74aadca57cfaccf608d9de7d8786364b7a8d02600060030154604051611252916001600160a01b031690600090612123565b60405180910390a1600080610919565b60008080546001600160a01b0316331461128f57604051633057182d60e21b815260040160405180910390fd5b6040514790600090339083908381818185875af1925050503d80600081146112d3576040519150601f19603f3d011682016040523d82523d6000602084013e6112d8565b606091505b50506040805184815282151560208201529192507f2aeb20ed0ead73e7bc740154a0b979547bc9e00691d84a700e6454ada9fe4679910160405180910390a190925090509091565b6000600301546001600160a01b0316331461134e57604051631387214760e01b815260040160405180910390fd5b7f7ad92e57a52c4e3e83ba624622b14e3a5efa0160dd6f9a7975c43ea66bad79ea6000600e015460405161138d916001600160a01b0316908490612123565b60405180910390a1600e80546001600160a01b0319166001600160a01b0392909216919091179055565b6000546001600160a01b031633146113e257604051633057182d60e21b815260040160405180910390fd5b6010805463ffffffff83811663ffffffff1983168117909355604080519190921680825260208201939093527f581878c50ce0b9e3ff58adfe29b7a807191bef3c1623340a0ad1d0d8433ebf869101610709565b6000546001600160a01b0316331461146157604051633057182d60e21b815260040160405180910390fd5b61c4e08163ffffffff16111561148a5760405163024c1d4b60e31b815260040160405180910390fd5b6010805463ffffffff83811664010000000081810267ffffffff00000000198516179094556040805194909304919091168084526020840191909152917ff860ba522a6e820ac6577b201d9314604a19ad2e264913d8361821e3659568db9101610709565b6000600101546001600160a01b03163314801561150b57503315155b61156a5760405162461bcd60e51b815260206004820152602a60248201527f4e6f756e7344414f3a3a5f61636365707441646d696e3a2070656e64696e672060448201526961646d696e206f6e6c7960b01b60648201526084016106c6565b60008054600180546001600160a01b03198084166001600160a01b03838116918217909655911690915560405192909116917ff9ffabca9c8276e99321725bcb43fb076a6c66a54b7f21c4e8146d8519b417dc906115cb9084908490612123565b60405180910390a17fca4f2f25d0898edd99413412fb94012f9e54ec8142f9b093e7720646a95b16a9816000604051610709929190612123565b6000546001600160a01b0316331461163057604051633057182d60e21b815260040160405180910390fd5b60c88361ffff16108061164857506107d08361ffff16115b156116665760405163db8a74af60e01b815260040160405180910390fd5b6117708261ffff16111561168d5760405163143abf4360e21b815260040160405180910390fd5b8161ffff168361ffff1611156116b6576040516362c564d560e11b815260040160405180910390fd5b60006116c24382610829565b9050600060405180606001604052808661ffff1681526020018561ffff1681526020018463ffffffff1681525090506116fa81611b73565b815181516040805161ffff93841681529290911660208301527ffaeebe30d875e399189096ea49fea81bd41fe6dfc86ad3550639063219e60778910160405180910390a17f4bfb1235074b38f02e5cf8ba90f535905417c196a12654f65ee0584512d706428260200151826020015160405161178792919061ffff92831681529116602082015260400190565b60405180910390a160408083015182820151825163ffffffff9283168152911660208201527f5e3adb1066359dafa23c629f245d93543856115700821dcb4debc416f393c469910160405180910390a15050505050565b6000546001600160a01b0316331461180957604051633057182d60e21b815260040160405180910390fd5b601180546001600160a01b038381166001600160a01b03198316179092556040519116907f5f317d96631add203c522c8ecc74fd6144c936367e2205ac922331fb12b670b4906107099083908590612123565b6040805160608101825260008082526020820181905291810191909152600061189d8360405180606001604052806040815260200161229760409139611e2a565b600d85015490915060008190036118f45760405180606001604052806118c68760070154611e5a565b61ffff1681526020016118dc8760070154611e5a565b61ffff16815260006020909101529250611b6d915050565b63ffffffff8216600d860161190a6001846121e9565b8154811061191a5761191a6121fc565b600091825260209091206002909102015463ffffffff16116119ad57600d85016119456001836121e9565b81548110611955576119556121fc565b6000918252602091829020604080516060810182526002939093029091016001015461ffff8082168452620100008204169383019390935264010000000090920463ffffffff16918101919091529250611b6d915050565b8163ffffffff1685600d016000815481106119ca576119ca6121fc565b600091825260209091206002909102015463ffffffff1611156119ff5760405180606001604052806118c68760070154611e5a565b600080611a0d6001846121e9565b90505b81811115611b035760006002611a2684846121e9565b611a309190612212565b611a3a90836121e9565b9050600088600d018281548110611a5357611a536121fc565b60009182526020918290206040805180820182526002909302909101805463ffffffff9081168452825160608101845260019092015461ffff808216845262010000820416838701526401000000009004811692820192909252928201929092528051909250878216911603611ad457602001519550611b6d945050505050565b805163ffffffff80881691161015611aee57819350611afc565b611af96001836121e9565b92505b5050611a10565b86600d018281548110611b1857611b186121fc565b6000918252602091829020604080516060810182526002939093029091016001015461ffff8082168452620100008204169383019390935264010000000090920463ffffffff16918101919091529450505050505b92915050565b6000611bb4436040518060400160405280601c81526020017f626c6f636b206e756d6265722065786365656473203332206269747300000000815250611e2a565b600d549091508015801590611c01575063ffffffff8216600d611bd86001846121e9565b81548110611be857611be86121fc565b600091825260209091206002909102015463ffffffff16145b15611c8e5782600d611c146001846121e9565b81548110611c2457611c246121fc565b60009182526020918290208351600160029093029091019190910180549284015160409094015163ffffffff166401000000000267ffffffff000000001961ffff958616620100000263ffffffff1990951695909316949094179290921716919091179055505050565b5060408051808201825263ffffffff92831681526020808201948552600d805460018101825560009190915291517fd7b6990105719101dabeb77144f2a3385c8033acd3af97e9423a695e81ad1eb56002909302928301805491861663ffffffff19928316179055945180517fd7b6990105719101dabeb77144f2a3385c8033acd3af97e9423a695e81ad1eb690930180549282015191909401519094166401000000000267ffffffff000000001961ffff95861662010000029290961694909216939093179290921792909216179055565b6000819003611d6e575050565b60005b611d7c6001836121e9565b811015611124576000611d90826001612234565b90505b82811015611e2157838382818110611dad57611dad6121fc565b9050602002016020810190611dc29190611f5d565b6001600160a01b0316848484818110611ddd57611ddd6121fc565b9050602002016020810190611df29190611f5d565b6001600160a01b031603611e1957604051630254983f60e41b815260040160405180910390fd5b600101611d93565b50600101611d71565b60008163ffffffff841115611e525760405162461bcd60e51b81526004016106c69190612247565b509192915050565b600061ffff821115611e7f5760405163555abf0160e11b815260040160405180910390fd5b5090565b828054828255906000526020600020908101928215611ed6579160200282015b82811115611ed65781546001600160a01b0319166001600160a01b03843516178255602090920191600190910190611ea3565b50611e7f9291505b80821115611e7f5760008155600101611ede565b600060208284031215611f0457600080fd5b5035919050565b803563ffffffff81168114611f1f57600080fd5b919050565b600060208284031215611f3657600080fd5b611f3f82611f0b565b9392505050565b80356001600160a01b0381168114611f1f57600080fd5b600060208284031215611f6f57600080fd5b611f3f82611f46565b600080600060608486031215611f8d57600080fd5b611f9684611f46565b9250611fa460208501611f46565b9150611fb260408501611f46565b90509250925092565b803561ffff81168114611f1f57600080fd5b600060208284031215611fdf57600080fd5b611f3f82611fbb565b60008083601f840112611ffa57600080fd5b50813567ffffffffffffffff81111561201257600080fd5b6020830191508360208260051b850101111561202d57600080fd5b9250929050565b60008060008060008060a0878903121561204d57600080fd5b61205687611f46565b955061206460208801611f46565b9450604087013567ffffffffffffffff81111561208057600080fd5b61208c89828a01611fe8565b979a9699509760608101359660809091013595509350505050565b600080602083850312156120ba57600080fd5b823567ffffffffffffffff8111156120d157600080fd5b6120dd85828601611fe8565b90969095509350505050565b6000806000606084860312156120fe57600080fd5b61210784611fbb565b925061211560208501611fbb565b9150611fb260408501611f0b565b6001600160a01b0392831681529116602082015260400190565b6000604082016040835280865480835260608501915087600052602092508260002060005b828110156121875781546001600160a01b031684529284019260019182019101612162565b505050838103828501528481528590820160005b868110156121c7576001600160a01b036121b484611f46565b168252918301919083019060010161219b565b50979650505050505050565b634e487b7160e01b600052601160045260246000fd5b81810381811115611b6d57611b6d6121d3565b634e487b7160e01b600052603260045260246000fd5b60008261222f57634e487b7160e01b600052601260045260246000fd5b500490565b80820180821115611b6d57611b6d6121d3565b60006020808352835180602085015260005b8181101561227557858101830151858201604001528201612259565b506000604082860101526040601f19601f830116850101925050509291505056fe4e6f756e7344414f3a3a67657444796e616d696351756f72756d506172616d7341743a20626c6f636b206e756d62657220657863656564732033322062697473a2646970667358221220c5e5aef6847a19b009419ec27b21f32c87b71c941e50267d3a1a5da2521c32ae64736f6c63430008170033", + "nonce": "0x3", + "chainId": "0x1", + "accessList": null, + "type": null + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x89857e7b83a9aa57ade9d740ec6de5e57302eb3510327110e00e0b3b18622589", + "transactionType": "CREATE", + "contractName": "NounsDAODynamicQuorum", + "contractAddress": "0xb5aa61eff82ea7b4ea6443532df15b7d4b40c3a0", + "function": null, + "arguments": null, + "transaction": { + "from": "0x918895f466eb3cd5fb181626f8e1b2fd8a9d5192", + "to": null, + "gas": "0x3c5f4", + "value": null, + "input": "0x61027a61003a600b82828239805160001a60731461002d57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600436106100355760003560e01c8063bb2960751461003a575b600080fd5b61004d610048366004610131565b61005f565b60405190815260200160405180910390f35b6000808361006f866127106101f8565b610079919061020f565b90506000620f424082856040015163ffffffff1661009791906101f8565b6100a1919061020f565b9050600081856000015161ffff166100b99190610231565b905060006100cf866020015161ffff16836100e7565b90506100db8188610101565b98975050505050505050565b60008183106100f657816100f8565b825b90505b92915050565b600061271061011084846101f8565b6100f8919061020f565b803561ffff8116811461012c57600080fd5b919050565b600080600083850360a081121561014757600080fd5b84359350602085013592506060603f198201121561016457600080fd5b506040516060810181811067ffffffffffffffff8211171561019657634e487b7160e01b600052604160045260246000fd5b80604052506101a76040860161011a565b81526101b56060860161011a565b6020820152608085013563ffffffff811681146101d157600080fd5b604082015292959194509192509050565b634e487b7160e01b600052601160045260246000fd5b80820281158282048414176100fb576100fb6101e2565b60008261022c57634e487b7160e01b600052601260045260246000fd5b500490565b808201808211156100fb576100fb6101e256fea26469706673582212208d1cbada5250b0f0ee7f487f17b8024885b2c4a3e362b79a95a6ab87356ad76864736f6c63430008170033", + "nonce": "0x4", + "chainId": "0x1", + "accessList": null, + "type": null + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x8f40d8b469c009bde3cb810314babc483ea3e47073180ac4e43917424325f7da", + "transactionType": "CREATE", + "contractName": "NounsDAOFork", + "contractAddress": "0x3d4f1ee041c31afc0fbda4f058d34544d71eb6ad", + "function": null, + "arguments": null, + "transaction": { + "from": "0x918895f466eb3cd5fb181626f8e1b2fd8a9d5192", + "to": null, + "gas": "0x15fc5d", + "value": null, + "input": "0x61131761003a600b82828239805160001a60731461002d57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600436106100925760003560e01c8063704a3b1211610065578063704a3b12146101125780637a868d3e14610152578063aeaa6be614610172578063f667e1141461019257600080fd5b80630577a8461461009757806313d419f6146100b957806319244b17146100df5780636055f935146100f2575b600080fd5b8180156100a357600080fd5b506100b76100b2366004610efe565b6101b2565b005b6100cc6100c7366004610f4a565b6102f8565b6040519081526020015b60405180910390f35b6100cc6100ed366004610f4a565b610379565b8180156100fe57600080fd5b506100b761010d366004610efe565b6103a0565b81801561011e57600080fd5b5061013261012d366004610f4a565b6103c2565b604080516001600160a01b039384168152929091166020830152016100d6565b81801561015e57600080fd5b506100b761016d366004610f63565b61063c565b81801561017e57600080fd5b506100b761018d36600461104c565b6107e1565b81801561019e57600080fd5b506100b76101ad366004610f63565b610866565b60158301544210156101d7576040516366c8a93b60e01b815260040160405180910390fd5b6010830154604051633567f93d60e11b8152600160601b9091046001600160a01b0316908190636acff27a90610215903390879087906004016110dd565b600060405180830381600087803b15801561022f57600080fd5b505af1158015610243573d6000803e3d6000fd5b50505050336001600160a01b0316816001600160a01b031663d7e53db06040518163ffffffff1660e01b8152600401602060405180830381865afa15801561028f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102b3919061110b565b63ffffffff167f7e066a27b070725cdb5ae51be8128dc95d65af0841137f77ec895c775f69849985856040516102ea929190611138565b60405180910390a350505050565b600081601001600c9054906101000a90046001600160a01b03166001600160a01b031663aa34213b6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561034f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103739190611154565b92915050565b6000612710826017015461038c84610aa1565b6103969190611183565b610373919061119a565b60098301546103bd908490849084906001600160a01b0316610c1d565b505050565b6000806103d28360150154421090565b156103f0576040516366c8a93b60e01b815260040160405180910390fd5b600083601001600c9054906101000a90046001600160a01b031690506000816001600160a01b031663aa34213b6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561044c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104709190611154565b905061047b85610379565b811161049a57604051630698c25760e11b815260040160405180910390fd5b60008560160154426104ac91906111bc565b601187015460405163fb14694360e01b8152600481018390526001600160a01b03868116602483015292935091169063fb1469439060440160408051808303816000875af1158015610502573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061052691906111cf565b909550935061053f86868461053a83610aa1565b610ce7565b6000836001600160a01b031663c163de3d6040518163ffffffff1660e01b81526004016020604051808303816000875af1158015610581573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105a5919061110b565b6013880180546001600160a01b038981166001600160a01b0319928316811790935560148b018054918a1691909216811790915560158a0185905560408051928352602083019190915281018490526060810185905290915063ffffffff8216907fb924f7ec9fa839e53ec987276a1a33b95a0aa0796ca86204f365925ac2dbded99060800160405180910390a250505050915091565b6015870154421015610661576040516366c8a93b60e01b815260040160405180910390fd5b6010870154600160601b90046001600160a01b031660005b8681101561072357600a8901546001600160a01b03166342842e0e33848b8b868181106106a8576106a8611209565b6040516001600160e01b031960e088901b1681526001600160a01b03958616600482015294909316602485015250602090910201356044820152606401600060405180830381600087803b1580156106ff57600080fd5b505af1158015610713573d6000803e3d6000fd5b5050600190920191506106799050565b50336001600160a01b0316816001600160a01b031663d7e53db06040518163ffffffff1660e01b8152600401602060405180830381865afa15801561076c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610790919061110b565b63ffffffff167f9a9bbe8a8a2c2b1e1d690cccd211b60ef1d2976f404800ed20604e57d3ed0f2d8989898989896040516107cf9695949392919061121f565b60405180910390a35050505050505050565b60098401546001600160a01b03908116908216036108125760405163c37a1e1760e01b815260040160405180910390fd5b61081e84848484610c1d565b604080518381526001600160a01b03831660208201527f855244575056ebffdfb115e332dfa96f1cd148bfe5bf486758fdd2d55b6fe9eb91015b60405180910390a150505050565b6015870154421061088a57604051635a7d97a760e11b815260040160405180910390fd5b6010870154600988015460138901546001600160a01b03600160601b909304831692918216916108c1918b91168961053a83610aa1565b60005b8781101561096e57600a8a01546001600160a01b03166323b872dd33848c8c868181106108f3576108f3611209565b6040516001600160e01b031960e088901b1681526001600160a01b03958616600482015294909316602485015250602090910201356044820152606401600060405180830381600087803b15801561094a57600080fd5b505af115801561095e573d6000803e3d6000fd5b5050600190920191506108c49050565b5060148901546040516374ea764760e01b81526001600160a01b03909116906374ea7647906109a59033908c908c906004016110dd565b600060405180830381600087803b1580156109bf57600080fd5b505af11580156109d3573d6000803e3d6000fd5b50505050336001600160a01b03166001836001600160a01b031663d7e53db06040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a21573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a45919061110b565b610a4f919061127e565b63ffffffff167f96ca5dab079aba8ed43c71a25c6090b5bce0e3f9ebcb4080816655b7a2d5a36f8a8a8a8a8a8a604051610a8e9695949392919061121f565b60405180910390a3505050505050505050565b600081601001600c9054906101000a90046001600160a01b03166001600160a01b0316639b3c1e226040518163ffffffff1660e01b8152600401602060405180830381865afa158015610af8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b1c9190611154565b600a83015460098401546040516370a0823160e01b81526001600160a01b0391821660048201529116906370a0823190602401602060405180830381865afa158015610b6c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b909190611154565b83600a0160009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610be5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c099190611154565b610c1391906112a2565b61037391906112a2565b83546001600160a01b03163314610c4757604051633057182d60e21b815260040160405180910390fd5b601084015460405163341f601360e21b8152600160601b9091046001600160a01b03169063d07d804c90610c83908690869086906004016112b5565b600060405180830381600087803b158015610c9d57600080fd5b505af1158015610cb1573d6000803e3d6000fd5b505050507e5508ab2be53c6629a9db1afe9702076dc2c4c4f344d60e711a315891d7141e838383604051610858939291906112b5565b60098401546001600160a01b0316600082610d03858431611183565b610d0d919061119a565b6040516364a197f360e01b81526001600160a01b03878116600483015260248201839052919250908316906364a197f390604401600060405180830381600087803b158015610d5b57600080fd5b505af1158015610d6f573d6000803e3d6000fd5b50505050601286015460005b81811015610ea8576000886012018281548110610d9a57610d9a611209565b60009182526020822001546040516370a0823160e01b81526001600160a01b03888116600483015290911692508790899084906370a0823190602401602060405180830381865afa158015610df3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e179190611154565b610e219190611183565b610e2b919061119a565b90508015610e9e576040516323e5d69960e21b81526001600160a01b038a81166004830152838116602483015260448201839052871690638f975a6490606401600060405180830381600087803b158015610e8557600080fd5b505af1158015610e99573d6000803e3d6000fd5b505050505b5050600101610d7b565b5050505050505050565b60008083601f840112610ec457600080fd5b50813567ffffffffffffffff811115610edc57600080fd5b6020830191508360208260051b8501011115610ef757600080fd5b9250929050565b600080600060408486031215610f1357600080fd5b83359250602084013567ffffffffffffffff811115610f3157600080fd5b610f3d86828701610eb2565b9497909650939450505050565b600060208284031215610f5c57600080fd5b5035919050565b60008060008060008060006080888a031215610f7e57600080fd5b87359650602088013567ffffffffffffffff80821115610f9d57600080fd5b610fa98b838c01610eb2565b909850965060408a0135915080821115610fc257600080fd5b610fce8b838c01610eb2565b909650945060608a0135915080821115610fe757600080fd5b818a0191508a601f830112610ffb57600080fd5b81358181111561100a57600080fd5b8b602082850101111561101c57600080fd5b60208301945080935050505092959891949750929550565b6001600160a01b038116811461104957600080fd5b50565b6000806000806060858703121561106257600080fd5b84359350602085013567ffffffffffffffff81111561108057600080fd5b61108c87828801610eb2565b90945092505060408501356110a081611034565b939692955090935050565b81835260006001600160fb1b038311156110c457600080fd5b8260051b80836020870137939093016020019392505050565b6001600160a01b038416815260406020820181905260009061110290830184866110ab565b95945050505050565b60006020828403121561111d57600080fd5b815163ffffffff8116811461113157600080fd5b9392505050565b60208152600061114c6020830184866110ab565b949350505050565b60006020828403121561116657600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b80820281158282048414176103735761037361116d565b6000826111b757634e487b7160e01b600052601260045260246000fd5b500490565b808201808211156103735761037361116d565b600080604083850312156111e257600080fd5b82516111ed81611034565b60208401519092506111fe81611034565b809150509250929050565b634e487b7160e01b600052603260045260246000fd5b60608152600061123360608301888a6110ab565b82810360208401526112468187896110ab565b90508281036040840152838152838560208301376000602085830101526020601f19601f860116820101915050979650505050505050565b63ffffffff82811682821603908082111561129b5761129b61116d565b5092915050565b818103818111156103735761037361116d565b6040815260006112c96040830185876110ab565b905060018060a01b038316602083015294935050505056fea2646970667358221220fd802a6052690f91ee05466d04b1d277dd3a3f33cdfc92bf23e0ec0373c36d9a64736f6c63430008170033", + "nonce": "0x5", + "chainId": "0x1", + "accessList": null, + "type": null + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0xa603f6aebe14018d59b50528a7c8fa404c310e7a23e016e114a33fadfe838f2a", + "transactionType": "CREATE", + "contractName": "NounsDAOProposals", + "contractAddress": "0xac6eefcc699047856c07c8679e1339903bd5ffcc", + "function": null, + "arguments": null, + "transaction": { + "from": "0x918895f466eb3cd5fb181626f8e1b2fd8a9d5192", + "to": null, + "gas": "0x4ffaae", + "value": null, + "input": "0x6147f961003a600b82828239805160001a60731461002d57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600436106101155760003560e01c806383478b43116100ac578063b0a3fc381161007b578063b0a3fc38146102ac578063b2faf4d4146102cc578063b7aa3e57146102ec578063ddb639831461030c578063f9df1e191461032c57600080fd5b806383478b431461021e578063853b94a01461023e57806392be51d814610265578063ac982f381461028557600080fd5b80633ce52dbe116100e85780633ce52dbe1461019e5780635e6ab1ac146101be57806373d0ed2f146101de5780637b55bff3146101fe57600080fd5b806320606b701461011a57806320660f531461015457806336e7048a14610174578063370d35771461017c575b600080fd5b6101417f8cad95687ba82c2ce50e74f7b754645e5117c3a5bec8151c0726d5857980a86681565b6040519081526020015b60405180910390f35b81801561016057600080fd5b5061014161016f3660046138a0565b61034c565b610141600a81565b81801561018857600080fd5b5061019c61019736600461394f565b6104bc565b005b8180156101aa57600080fd5b5061019c6101b936600461394f565b6104ea565b8180156101ca57600080fd5b5061019c6101d936600461394f565b6109b1565b6101f16101ec36600461394f565b610cd5565b60405161014b9190613987565b81801561020a57600080fd5b5061019c6102193660046139af565b610cea565b81801561022a57600080fd5b5061019c610239366004613ab8565b610d4e565b6101417fd4eafb6bc770edecb5da52765bc3f50af948bfe1b8344cf115f8ee7fefe55ec781565b61027861027336600461394f565b610daf565b60405161014b9190613b9c565b6101417fe5a9e6d2702042f3612beac0f605312204baddec2d19d1338da7e37e6c67d6ee81565b8180156102b857600080fd5b5061019c6102c7366004613ca3565b610f2c565b8180156102d857600080fd5b5061019c6102e736600461394f565b610f87565b8180156102f857600080fd5b5061019c610307366004613d25565b61118f565b61031f61031a36600461394f565b611211565b60405161014b9190613db5565b81801561033857600080fd5b5061019c610347366004613ee4565b61144f565b6000845160000361037057604051637a4783fb60e01b815260040160405180910390fd5b61037984611738565b6103a36040518060600160405280600063ffffffff16815260200160008152602001600081525090565b60088701546103b3906001613fb8565b600888018190556103c3906117cf565b63ffffffff1681526103d487611838565b602082018190526103e69088906119b4565b6040820181905281516020830151600092610407928b929091908a896119c4565b90506000806104238a8a8a8a886000015163ffffffff16611b8d565b91509150805160000361044957604051637a4783fb60e01b815260040160405180910390fd5b8360400151821161046d5760405163ead8241560e01b815260040160405180910390fd5b805161048290601285019060208401906132b4565b506104a7838261049f87602001518e611e5290919063ffffffff16565b8b8b8b611e6c565b5050905163ffffffff16979650505050505050565b6000818152600b830160205260408120906104d78483611f46565b90506104e4848383611f7e565b50505050565b60006104f683836121b2565b9050600281600a81111561050c5761050c613971565b14806105295750600381600a81111561052757610527613971565b145b806105455750600681600a81111561054357610543613971565b145b806105615750600781600a81111561055f5761055f613971565b145b8061057d5750600881600a81111561057b5761057b613971565b145b1561059b57604051635598baf360e01b815260040160405180910390fd5b6000828152600b840160205260408120600180820154600a87015492936001600160a01b039182169390911691829063782d6fe19085906105dc9043613fcb565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401602060405180830381865afa158015610625573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106499190613fde565b6001600160601b031690506000336001600160a01b0316846001600160a01b03161490506000856012018054806020026020016040519081016040528092919081815260200182805480156106c757602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116106a9575b5050505050905060005b81518110156107d257828061071057508181815181106106f3576106f361400e565b60200260200101516001600160a01b0316336001600160a01b0316145b9250846001600160a01b031663782d6fe18383815181106107335761073361400e565b60200260200101516001436107489190613fcb565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401602060405180830381865afa158015610791573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107b59190613fde565b6107c8906001600160601b031685613fb8565b93506001016106d1565b5081806107e3575085600201548311155b6108475760405162461bcd60e51b815260206004820152602a60248201527f4e6f756e7344414f3a3a63616e63656c3a2070726f706f7365722061626f7665604482015269081d1a1c995cda1bdb1960b21b60648201526084015b60405180910390fd5b600e8601805460ff1916600117905560006108628a88611f46565b905060005b600588015481101561097157816001600160a01b031663591fcdfe8960050183815481106108975761089761400e565b60009182526020909120015460068b0180546001600160a01b0390921691859081106108c5576108c561400e565b90600052602060002001548b60070185815481106108e5576108e561400e565b906000526020600020018c60080186815481106109045761090461400e565b906000526020600020018d600401546040518663ffffffff1660e01b81526004016109339594939291906140db565b600060405180830381600087803b15801561094d57600080fd5b505af1158015610961573d6000803e3d6000fd5b5050600190920191506108679050565b506040518981527f789cf55be980739dad1d0699b93b58e806b51c9d96619bfa8fe0a28abaa7b30c9060200160405180910390a150505050505050505050565b60046109bd83836121b2565b600a8111156109ce576109ce613971565b14610a415760405162461bcd60e51b815260206004820152603f60248201527f4e6f756e7344414f3a3a71756575653a2070726f706f73616c2063616e206f6e60448201527f6c79206265207175657565642069662069742069732073756363656564656400606482015260840161083e565b6000818152600b83016020526040812090610a5c8483611f46565b90506000816001600160a01b0316636a42b8f86040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a9e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ac29190614127565b610acc9042613fb8565b905060005b6005840154811015610c8d57610c8583856005018381548110610af657610af661400e565b6000918252602090912001546006870180546001600160a01b039092169185908110610b2457610b2461400e565b9060005260206000200154876007018581548110610b4457610b4461400e565b906000526020600020018054610b5990614024565b80601f0160208091040260200160405190810160405280929190818152602001828054610b8590614024565b8015610bd25780601f10610ba757610100808354040283529160200191610bd2565b820191906000526020600020905b815481529060010190602001808311610bb557829003601f168201915b5050505050886008018681548110610bec57610bec61400e565b906000526020600020018054610c0190614024565b80601f0160208091040260200160405190810160405280929190818152602001828054610c2d90614024565b8015610c7a5780601f10610c4f57610100808354040283529160200191610c7a565b820191906000526020600020905b815481529060010190602001808311610c5d57829003601f168201915b5050505050876123ab565b600101610ad1565b506004830181905560408051858152602081018390527f9a2e42fd6722813d69113e7d0079d3d940171428df7373df9c7f7617cfda2892910160405180910390a15050505050565b6000610ce183836121b2565b90505b92915050565b610cf8888888888888612554565b336001600160a01b0316877fd92cc1350c3c114b08bfa9ca07e42b8d07adf3c440ac299943edfbfb9be890ac888888888888604051610d3c9695949392919061421b565b60405180910390a35050505050505050565b610d5c878787878787612554565b336001600160a01b0316867f2588d794bdaac5e181a3efca6937bf6bac4e2f42f43dcfcf0492b3d8b54be0658787878787604051610d9e95949392919061429d565b60405180910390a350505050505050565b610e37604051806101e001604052806000815260200160006001600160a01b03168152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160001515815260200160001515815260200160001515815260200160008152602001600081525090565b6000828152600b8401602090815260409182902082516101e081018452815463ffffffff90811680835260018401546001600160a01b031694830194909452600283015494820194909452909290916060830191610e979188916125f916565b81526004830154602082015260098301546040820152600a8301546060820152600b8301546080820152600c83015460a0820152600d83015460c0820152600e83015460ff808216151560e0840152610100808304821615159084015262010000909104161515610120820152601083015461014082015260119092015463ffffffff16610160909201919091529392505050565b6000858152600b870160205260409020610f47878783612652565b336001600160a01b0316867fb326c35bcac6caacafa6cd1190bb9dc1a4e0aad7a7985e193818797dfbec990587878787604051610d9e9493929190614327565b60038201546001600160a01b0316610fb257604051631efc808d60e31b815260040160405180910390fd5b60038201546001600160a01b03163314610fdf57604051631387214760e01b815260040160405180910390fd5b6007610feb83836121b2565b600a811115610ffc57610ffc613971565b0361101a57604051636c0a12d560e01b815260040160405180910390fd5b6000818152600b830160205260408120600e8101805461ff001916610100179055906110468483611f46565b905060005b600583015481101561115557816001600160a01b031663591fcdfe84600501838154811061107b5761107b61400e565b6000918252602090912001546006860180546001600160a01b0390921691859081106110a9576110a961400e565b90600052602060002001548660070185815481106110c9576110c961400e565b906000526020600020018760080186815481106110e8576110e861400e565b9060005260206000200188600401546040518663ffffffff1660e01b81526004016111179594939291906140db565b600060405180830381600087803b15801561113157600080fd5b505af1158015611145573d6000803e3d6000fd5b50506001909201915061104b9050565b506040518381527fde0cea2a3a0097cc3d981d40c375407760e85bc9c5e69aea449ac3885f8615c69060200160405180910390a150505050565b600082826040516111a192919061434e565b60408051918290038220336000818152600f89016020908152848220848352905292909220805460ff191660011790559250907f45f194850d9c26cfb50dad5456a1c64997b6a4d461d0159f372282ba183d854d90611203908690869061435e565b60405180910390a250505050565b6112b76040518061026001604052806000815260200160006001600160a01b03168152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160001515815260200160001515815260200160001515815260200160008152602001600081526020016060815260200160008152602001600081526020016000151581525090565b6000828152600b84016020908152604091829020825161026081018452815463ffffffff90811680835260018401546001600160a01b0316948301949094526002830154948201949094529092909160608301916113179188916125f916565b815260048301546020808301919091526009840154604080840191909152600a8501546060840152600b8501546080840152600c85015460a0840152600d85015460c0840152600e85015460ff808216151560e08601526101008083048216151590860152620100009091041615156101208401526010850154610140840152601185015463ffffffff1661016084015260128501805482518185028101850190935280835261018090940193919290919083018282801561140257602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116113e4575b505050918352505060118301546001600160401b03600160401b820481166020840152600160801b90910416604082015260139092015460ff161515606090920191909152905092915050565b61145883611738565b835160000361147a57604051637a4783fb60e01b815260040160405180910390fd5b6000858152600b870160205260409020600a61149688886121b2565b600a8111156114a7576114a7613971565b146114c5576040516339abb30760e21b815260040160405180910390fd5b60018101546001600160a01b031633146114f257604051631d6b368d60e01b815260040160405180910390fd5b60008160120180548060200260200160405190810160405280929190818152602001828054801561154c57602002820191906000526020600020905b81546001600160a01b0316815260019091019060200180831161152e575b5050505050905080518651146115755760405163b92ba76160e01b815260040160405180910390fd5b6000876115833388886126e2565b604051602001611594929190614372565b604051602081830303815290604052905060005b8751811015611666576115f68a838a84815181106115c8576115c861400e565b60200260200101517fe5a9e6d2702042f3612beac0f605312204baddec2d19d1338da7e37e6c67d6ee61292d565b8781815181106116085761160861400e565b6020026020010151602001516001600160a01b031683828151811061162f5761162f61400e565b60200260200101516001600160a01b03161461165e57604051631d6b368d60e01b815260040160405180910390fd5b6001016115a8565b508551805161167f9160058601916020909101906132b4565b5060208087015180516116989260068701920190613315565b50604086015180516116b4916007860191602090910190613350565b50606086015180516116d09160088601916020909101906133a2565b50336001600160a01b0316887fd92cc1350c3c114b08bfa9ca07e42b8d07adf3c440ac299943edfbfb9be890ac886000015189602001518a604001518b606001518b8b6040516117259695949392919061421b565b60405180910390a3505050505050505050565b602081015151815151141580611755575060408101515181515114155b80611767575060608101515181515114155b156117855760405163ccb0ce3f60e01b815260040160405180910390fd5b8051516000036117a857604051630f24cd7360e01b815260040160405180910390fd5b805151600a10156117cc576040516308e3b1eb60e11b815260040160405180910390fd5b50565b600063ffffffff8211156118345760405162461bcd60e51b815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203360448201526532206269747360d01b606482015260840161083e565b5090565b600081601001600c9054906101000a90046001600160a01b03166001600160a01b0316639b3c1e226040518163ffffffff1660e01b8152600401602060405180830381865afa15801561188f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118b39190614127565b600a83015460098401546040516370a0823160e01b81526001600160a01b0391821660048201529116906370a0823190602401602060405180830381865afa158015611903573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119279190614127565b83600a0160009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561197c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119a09190614127565b6119aa9190613fcb565b610ce49190613fcb565b6000610ce18360060154836129f1565b601086015460009081906119ee906119e990600160401b900463ffffffff1643613fb8565b612a0a565b905060008860040154826001600160401b0316611a0b9190613fb8565b90506000896005015482611a1f9190613fb8565b63ffffffff808b166000818152600b8e01602090815260409091208054938a166401000000000267ffffffffffffffff199094169092179290921781556001810180546001600160a01b03191633179055600281018b905588518051919750929350611a9192600588019201906132b4565b506020808701518051611aaa9260068801920190613315565b5060408601518051611ac6916007870191602090910190613350565b5060608601518051611ae29160088701916020909101906133a2565b5060098401829055600a840181905560108401879055611b01436117cf565b60118501805463ffffffff191663ffffffff92909216919091179055611b26426117cf565b6011850180546001600160401b03909516600160401b026fffffffffffffffff00000000000000001963ffffffff9390931664010000000002929092166fffffffffffffffffffffffff000000001990951694909417179092555090979650505050505050565b600a8501546000906060906001600160a01b031682611bad3388886126e2565b905087516001600160401b03811115611bc857611bc861347d565b604051908082528060200260200182016040528015611bf1578160200160208202803683370190505b5092506000805b8951811015611d7b57611c468b848c8481518110611c1857611c1861400e565b60200260200101517fd4eafb6bc770edecb5da52765bc3f50af948bfe1b8344cf115f8ee7fefe55ec761292d565b60008a8281518110611c5a57611c5a61400e565b6020026020010151602001519050611c728c82612a72565b60006001600160a01b03861663782d6fe183611c8f600143613fcb565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401602060405180830381865afa158015611cd8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cfc9190613fde565b6001600160601b0316905080600003611d16575050611d73565b818785611d2281614398565b965081518110611d3457611d3461400e565b6001600160a01b039283166020918202929092018101919091529083166000908152600c8f0190915260409020899055611d6e8189613fb8565b975050505b600101611bf8565b508851811015611d89578084525b611d938a33612a72565b336000818152600c8c01602052604090208790556001600160a01b0384169063782d6fe190611dc3600143613fcb565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401602060405180830381865afa158015611e0c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e309190613fde565b611e43906001600160601b031686613fb8565b94505050509550959350505050565b6000610ce1611e618443612b28565b5161ffff16836129f1565b855483516020850151604080870151606088015160098c0154600a8d015493517f7d84a6263ae0d98d3329bd7b46bb4e8d6f98cd35a7adb45c274c8b7fd5ebd5e097611ecf9763ffffffff90911696339691959094909390929091908c906143b1565b60405180910390a185546011870154600288015460405163ffffffff808616947fd9d12651716feaac10e3b79bd2960ad42ebfd84969b71a2e226ec99972a8712e94611f369491909216928b926001600160401b03600160401b9091041691908b9061444f565b60405180910390a2505050505050565b601381015460009060ff1615611f6a575060188201546001600160a01b0316610ce4565b5060098201546001600160a01b0316610ce4565b60058254611f9390859063ffffffff166121b2565b600a811115611fa457611fa4613971565b14612019576040805162461bcd60e51b81526020600482015260248101919091527f4e6f756e7344414f3a3a657865637574653a2070726f706f73616c2063616e2060448201527f6f6e6c7920626520657865637574656420696620697420697320717565756564606482015260840161083e565b601583015442101561203e57604051633183594360e21b815260040160405180910390fd5b600e8201805462ff000019166201000017905560005b600583015481101561217057816001600160a01b0316630825f38f8460050183815481106120845761208461400e565b6000918252602090912001546006860180546001600160a01b0390921691859081106120b2576120b261400e565b90600052602060002001548660070185815481106120d2576120d261400e565b906000526020600020018760080186815481106120f1576120f161400e565b9060005260206000200188600401546040518663ffffffff1660e01b81526004016121209594939291906140db565b6000604051808303816000875af115801561213f573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526121679190810190614494565b50600101612054565b50815460405163ffffffff90911681527f712ae1383f79ac853f8d882153778e0260ef8f03b504e2866e0593e04d2b291f9060200160405180910390a1505050565b600081836008015410156122145760405162461bcd60e51b8152602060048201526024808201527f4e6f756e7344414f3a3a73746174653a20696e76616c69642070726f706f73616044820152631b081a5960e21b606482015260840161083e565b6000828152600b840160205260409020600e810154610100900460ff1615612240576008915050610ce4565b600e81015460ff1615612257576002915050610ce4565b6011810154600160401b90046001600160401b0316431161227c57600a915050610ce4565b80600901544311612291576000915050610ce4565b80600a015443116122a6576001915050610ce4565b6011810154600160801b90046001600160401b031643116122cb576009915050610ce4565b6122d58482612e3d565b156122e4576003915050610ce4565b80600401546000036122fa576004915050610ce4565b600e81015462010000900460ff1615612317576007915050610ce4565b6123218482611f46565b6001600160a01b031663c1a287e26040518163ffffffff1660e01b8152600401602060405180830381865afa15801561235e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123829190614127565b81600401546123919190613fb8565b42106123a1576006915050610ce4565b6005915050610ce4565b856001600160a01b031663f2b0653786868686866040516020016123d395949392919061450a565b604051602081830303815290604052805190602001206040518263ffffffff1660e01b815260040161240791815260200190565b602060405180830381865afa158015612424573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124489190614543565b156124d45760405162461bcd60e51b815260206004820152605060248201527f4e6f756e7344414f3a3a71756575654f72526576657274496e7465726e616c3a60448201527f206964656e746963616c2070726f706f73616c20616374696f6e20616c72656160648201526f6479207175657565642061742065746160801b608482015260a40161083e565b604051633a66f90160e01b81526001600160a01b03871690633a66f90190612508908890889088908890889060040161450a565b6020604051808303816000875af1158015612527573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061254b9190614127565b50505050505050565b61257d604051806080016040528086815260200185815260200184815260200183815250611738565b6000858152600b870160205260409020612598878783612652565b84516125ad90600583019060208801906132b4565b5083516125c39060068301906020870190613315565b5082516125d99060078301906020860190613350565b5081516125ef90600883019060208501906133a2565b5050505050505050565b6000818152600b8301602052604081206010810154820361261f57600301549050610ce4565b600c8101546010820154601183015461264a92919061264590889063ffffffff16612b28565b612e73565b949350505050565b600a61265e84846121b2565b600a81111561266f5761266f613971565b1461268d576040516339abb30760e21b815260040160405180910390fd5b60018101546001600160a01b031633146126ba57604051631d6b368d60e01b815260040160405180910390fd5b6012810154156126dd57604051630e13f93360e11b815260040160405180910390fd5b505050565b606060008360400151516001600160401b038111156127035761270361347d565b60405190808252806020026020018201604052801561272c578160200160208202803683370190505b50905060005b84604001515181101561278957846040015181815181106127555761275561400e565b6020026020010151805190602001208282815181106127765761277661400e565b6020908102919091010152600101612732565b5060008460600151516001600160401b038111156127a9576127a961347d565b6040519080825280602002602001820160405280156127d2578160200160208202803683370190505b50905060005b85606001515181101561282f57856060015181815181106127fb576127fb61400e565b60200260200101518051906020012082828151811061281c5761281c61400e565b60209081029190910101526001016127d8565b508451604051879161284391602001614565565b60405160208183030381529060405280519060200120866020015160405160200161286e91906145a4565b604051602081830303815290604052805190602001208460405160200161289591906145a4565b60405160208183030381529060405280519060200120846040516020016128bc91906145a4565b60408051601f1981840301815282825280516020918201208b518c8301206001600160a01b0390981691840191909152908201949094526060810192909252608082015260a081019190915260c081019190915260e001604051602081830303815290604052925050509392505050565b81518051602091820120818401516001600160a01b03166000908152600f870183526040808220838352909352919091205460ff161561298057604051634260f73960e01b815260040160405180910390fd5b60006129928386866040015130612efb565b90506129a78460200151828660000151612ff3565b6129c457604051638baa579f60e01b815260040160405180910390fd5b83604001514211156129e957604051630819bdcd60e01b815260040160405180910390fd5b505050505050565b6000612710612a0084846145ce565b610ce191906145e5565b60006001600160401b038211156118345760405162461bcd60e51b815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203660448201526534206269747360d01b606482015260840161083e565b6001600160a01b0381166000908152600c8301602052604090205480156126dd576000612a9f84836121b2565b9050600981600a811115612ab557612ab5613971565b1480612ad25750600181600a811115612ad057612ad0613971565b145b80612aee5750600081600a811115612aec57612aec613971565b145b80612b0a5750600a81600a811115612b0857612b08613971565b145b156104e4576040516306bee79560e01b815260040160405180910390fd5b60408051606081018252600080825260208201819052918101919091526000612b698360405180606001604052806040815260200161478460409139613054565b600d8501549091506000819003612bc0576040518060600160405280612b928760070154613084565b61ffff168152602001612ba88760070154613084565b61ffff16815260006020909101529250610ce4915050565b63ffffffff8216600d8601612bd6600184613fcb565b81548110612be657612be661400e565b600091825260209091206002909102015463ffffffff1611612c7957600d8501612c11600183613fcb565b81548110612c2157612c2161400e565b6000918252602091829020604080516060810182526002939093029091016001015461ffff8082168452620100008204169383019390935264010000000090920463ffffffff16918101919091529250610ce4915050565b8163ffffffff1685600d01600081548110612c9657612c9661400e565b600091825260209091206002909102015463ffffffff161115612ccb576040518060600160405280612b928760070154613084565b600080612cd9600184613fcb565b90505b81811115612dcf5760006002612cf28484613fcb565b612cfc91906145e5565b612d069083613fcb565b9050600088600d018281548110612d1f57612d1f61400e565b60009182526020918290206040805180820182526002909302909101805463ffffffff9081168452825160608101845260019092015461ffff808216845262010000820416838701526401000000009004811692820192909252928201929092528051909250878216911603612da057602001519550610ce4945050505050565b805163ffffffff80881691161015612dba57819350612dc8565b612dc5600183613fcb565b92505b5050612cdc565b86600d018281548110612de457612de461400e565b6000918252602091829020604080516060810182526002939093029091016001015461ffff8082168452620100008204169383019390935264010000000090920463ffffffff1691810191909152979650505050505050565b600b810154600c820154600091908111158061264a57508254612e6b90859063ffffffff908116906125f916565b119392505050565b60008083612e83866127106145ce565b612e8d91906145e5565b90506000620f424082856040015163ffffffff16612eab91906145ce565b612eb591906145e5565b9050600081856000015161ffff16612ecd9190613fb8565b90506000612ee3866020015161ffff16836130a9565b9050612eef81886129f1565b98975050505050505050565b600080858585604051602001612f1393929190614607565b60408051601f198184030181528282528051602091820120838301835260098452684e6f756e732044414f60b81b9382019390935281517f8cad95687ba82c2ce50e74f7b754645e5117c3a5bec8151c0726d5857980a866818301527fe1dd93b3612547b4bb7c3d429f3df8508d84f5a4f63b5e2e44340b94698e6b3b818401524660608201526001600160a01b0387166080808301919091528351808303909101815260a0820193849052805192019190912061190160f01b835260a2820181905260c29091018390526042909120919250905b979650505050505050565b600080600061300285856130bf565b9092509050600081600481111561301b5761301b613971565b1480156130395750856001600160a01b0316826001600160a01b0316145b8061304a575061304a868686613104565b9695505050505050565b60008163ffffffff84111561307c5760405162461bcd60e51b815260040161083e9190614634565b509192915050565b600061ffff8211156118345760405163555abf0160e11b815260040160405180910390fd5b60008183106130b85781610ce1565b5090919050565b60008082516041036130f55760208301516040840151606085015160001a6130e9878285856131f0565b945094505050506130fd565b506000905060025b9250929050565b6000806000856001600160a01b0316631626ba7e60e01b868660405160240161312e929190614647565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b031990941693909317909252905161316c9190614660565b600060405180830381855afa9150503d80600081146131a7576040519150601f19603f3d011682016040523d82523d6000602084013e6131ac565b606091505b50915091508180156131c057506020815110155b801561304a57508051630b135d3f60e11b906131e59083016020908101908401614127565b149695505050505050565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a083111561322757506000905060036132ab565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa15801561327b573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b0381166132a4576000600192509250506132ab565b9150600090505b94509492505050565b828054828255906000526020600020908101928215613309579160200282015b8281111561330957825182546001600160a01b0319166001600160a01b039091161782556020909201916001909101906132d4565b506118349291506133f4565b828054828255906000526020600020908101928215613309579160200282015b82811115613309578251825591602001919060010190613335565b828054828255906000526020600020908101928215613396579160200282015b82811115613396578251829061338690826146c4565b5091602001919060010190613370565b50611834929150613409565b8280548282559060005260206000209081019282156133e8579160200282015b828111156133e857825182906133d890826146c4565b50916020019190600101906133c2565b50611834929150613426565b5b8082111561183457600081556001016133f5565b8082111561183457600061341d8282613443565b50600101613409565b8082111561183457600061343a8282613443565b50600101613426565b50805461344f90614024565b6000825580601f1061345f575050565b601f0160209004906000526020600020908101906117cc91906133f4565b634e487b7160e01b600052604160045260246000fd5b604051606081016001600160401b03811182821017156134b5576134b561347d565b60405290565b604051608081016001600160401b03811182821017156134b5576134b561347d565b604051601f8201601f191681016001600160401b03811182821017156135055761350561347d565b604052919050565b60006001600160401b038211156135265761352661347d565b5060051b60200190565b60006001600160401b038211156135495761354961347d565b50601f01601f191660200190565b600082601f83011261356857600080fd5b813561357b61357682613530565b6134dd565b81815284602083860101111561359057600080fd5b816020850160208301376000918101602001919091529392505050565b80356001600160a01b03811681146135c457600080fd5b919050565b600082601f8301126135da57600080fd5b813560206135ea6135768361350d565b82815260059290921b8401810191818101908684111561360957600080fd5b8286015b848110156136995780356001600160401b038082111561362d5760008081fd5b908801906060828b03601f19018113156136475760008081fd5b61364f613493565b87840135838111156136615760008081fd5b61366f8d8a83880101613557565b825250604092506136818385016135ad565b8189015292013590820152835291830191830161360d565b509695505050505050565b600082601f8301126136b557600080fd5b813560206136c56135768361350d565b8083825260208201915060208460051b8701019350868411156136e757600080fd5b602086015b84811015613699576136fd816135ad565b83529183019183016136ec565b600082601f83011261371b57600080fd5b8135602061372b6135768361350d565b8083825260208201915060208460051b87010193508684111561374d57600080fd5b602086015b848110156136995780358352918301918301613752565b600082601f83011261377a57600080fd5b8135602061378a6135768361350d565b82815260059290921b840181019181810190868411156137a957600080fd5b8286015b848110156136995780356001600160401b038111156137cc5760008081fd5b6137da8986838b0101613557565b8452509183019183016137ad565b6000608082840312156137fa57600080fd5b6138026134bb565b905081356001600160401b038082111561381b57600080fd5b613827858386016136a4565b8352602084013591508082111561383d57600080fd5b6138498583860161370a565b6020840152604084013591508082111561386257600080fd5b61386e85838601613769565b6040840152606084013591508082111561388757600080fd5b5061389484828501613769565b60608301525092915050565b600080600080600060a086880312156138b857600080fd5b8535945060208601356001600160401b03808211156138d657600080fd5b6138e289838a016135c9565b955060408801359150808211156138f857600080fd5b61390489838a016137e8565b9450606088013591508082111561391a57600080fd5b5061392788828901613557565b925050608086013563ffffffff8116811461394157600080fd5b809150509295509295909350565b6000806040838503121561396257600080fd5b50508035926020909101359150565b634e487b7160e01b600052602160045260246000fd5b60208101600b83106139a957634e487b7160e01b600052602160045260246000fd5b91905290565b600080600080600080600080610100898b0312156139cc57600080fd5b883597506020890135965060408901356001600160401b03808211156139f157600080fd5b6139fd8c838d016136a4565b975060608b0135915080821115613a1357600080fd5b613a1f8c838d0161370a565b965060808b0135915080821115613a3557600080fd5b613a418c838d01613769565b955060a08b0135915080821115613a5757600080fd5b613a638c838d01613769565b945060c08b0135915080821115613a7957600080fd5b613a858c838d01613557565b935060e08b0135915080821115613a9b57600080fd5b50613aa88b828c01613557565b9150509295985092959890939650565b600080600080600080600060e0888a031215613ad357600080fd5b873596506020880135955060408801356001600160401b0380821115613af857600080fd5b613b048b838c016136a4565b965060608a0135915080821115613b1a57600080fd5b613b268b838c0161370a565b955060808a0135915080821115613b3c57600080fd5b613b488b838c01613769565b945060a08a0135915080821115613b5e57600080fd5b613b6a8b838c01613769565b935060c08a0135915080821115613b8057600080fd5b50613b8d8a828b01613557565b91505092959891949750929550565b815181526020808301516101e0830191613bc0908401826001600160a01b03169052565b5060408301516040830152606083015160608301526080830151608083015260a083015160a083015260c083015160c083015260e083015160e083015261010080840151818401525061012080840151818401525061014080840151613c298285018215159052565b505061016083810151151590830152610180808401511515908301526101a080840151908301526101c092830151929091019190915290565b60008083601f840112613c7457600080fd5b5081356001600160401b03811115613c8b57600080fd5b6020830191508360208285010111156130fd57600080fd5b60008060008060008060808789031215613cbc57600080fd5b863595506020870135945060408701356001600160401b0380821115613ce157600080fd5b613ced8a838b01613c62565b90965094506060890135915080821115613d0657600080fd5b50613d1389828a01613c62565b979a9699509497509295939492505050565b600080600060408486031215613d3a57600080fd5b8335925060208401356001600160401b03811115613d5757600080fd5b613d6386828701613c62565b9497909650939450505050565b60008151808452602080850194506020840160005b83811015613daa5781516001600160a01b031687529582019590820190600101613d85565b509495945050505050565b602081528151602082015260006020830151613ddc60408401826001600160a01b03169052565b506040830151606083015260608301516080830152608083015160a083015260a083015160c083015260c083015160e083015260e0830151610100818185015280850151915050610120818185015280850151915050610140818185015280850151915050610160613e518185018315159052565b8401519050610180613e668482018315159052565b84015190506101a0613e7b8482018315159052565b8401516101c0848101919091528401516101e08085019190915284015161026061020080860182905291925090613eb6610280860184613d70565b9086015161022086810191909152860151610240808701919091529095015115159301929092525090919050565b60008060008060008060c08789031215613efd57600080fd5b863595506020870135945060408701356001600160401b0380821115613f2257600080fd5b613f2e8a838b016135c9565b95506060890135915080821115613f4457600080fd5b613f508a838b016137e8565b94506080890135915080821115613f6657600080fd5b613f728a838b01613557565b935060a0890135915080821115613f8857600080fd5b50613f9589828a01613557565b9150509295509295509295565b634e487b7160e01b600052601160045260246000fd5b80820180821115610ce457610ce4613fa2565b81810381811115610ce457610ce4613fa2565b600060208284031215613ff057600080fd5b81516001600160601b038116811461400757600080fd5b9392505050565b634e487b7160e01b600052603260045260246000fd5b600181811c9082168061403857607f821691505b60208210810361405857634e487b7160e01b600052602260045260246000fd5b50919050565b6000815461406b81614024565b80855260206001838116801561408857600181146140a2576140d0565b60ff1985168884015283151560051b8801830195506140d0565b866000528260002060005b858110156140c85781548a82018601529083019084016140ad565b890184019650505b505050505092915050565b60018060a01b038616815284602082015260a06040820152600061410260a083018661405e565b8281036060840152614114818661405e565b9150508260808301529695505050505050565b60006020828403121561413957600080fd5b5051919050565b60008151808452602080850194506020840160005b83811015613daa57815187529582019590820190600101614155565b60005b8381101561418c578181015183820152602001614174565b50506000910152565b600081518084526141ad816020860160208601614171565b601f01601f19169290920160200192915050565b60008282518085526020808601955060208260051b8401016020860160005b8481101561420e57601f198684030189526141fc838351614195565b988401989250908301906001016141e0565b5090979650505050505050565b60c08152600061422e60c0830189613d70565b82810360208401526142408189614140565b9050828103604084015261425481886141c1565b9050828103606084015261426881876141c1565b9050828103608084015261427c8186614195565b905082810360a08401526142908185614195565b9998505050505050505050565b60a0815260006142b060a0830188613d70565b82810360208401526142c28188614140565b905082810360408401526142d681876141c1565b905082810360608401526142ea81866141c1565b90508281036080840152612eef8185614195565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b60408152600061433b6040830186886142fe565b8281036020840152612fe88185876142fe565b8183823760009101908152919050565b60208152600061264a6020830184866142fe565b8281526000825161438a816020850160208701614171565b919091016020019392505050565b6000600182016143aa576143aa613fa2565b5060010190565b63ffffffff8a1681526001600160a01b0389166020820152610120604082018190526000906143e28382018b613d70565b905082810360608401526143f6818a614140565b9050828103608084015261440a81896141c1565b905082810360a084015261441e81886141c1565b90508560c08401528460e084015282810361010084015261443f8185614195565b9c9b505050505050505050505050565b63ffffffff8616815260a06020820152600061446e60a0830187613d70565b6001600160401b0395909516604083015250606081019290925260809091015292915050565b6000602082840312156144a657600080fd5b81516001600160401b038111156144bc57600080fd5b8201601f810184136144cd57600080fd5b80516144db61357682613530565b8181528560208385010111156144f057600080fd5b614501826020830160208601614171565b95945050505050565b60018060a01b038616815284602082015260a06040820152600061453160a0830186614195565b82810360608401526141148186614195565b60006020828403121561455557600080fd5b8151801515811461400757600080fd5b815160009082906020808601845b838110156145985781516001600160a01b031685529382019390820190600101614573565b50929695505050505050565b815160009082906020808601845b83811015614598578151855293820193908201906001016145b2565b8082028115828204841417610ce457610ce4613fa2565b60008261460257634e487b7160e01b600052601260045260246000fd5b500490565b8381526000835161461f816020850160208801614171565b60209201918201929092526040019392505050565b602081526000610ce16020830184614195565b82815260406020820152600061264a6040830184614195565b60008251614672818460208701614171565b9190910192915050565b601f8211156126dd576000816000526020600020601f850160051c810160208610156146a55750805b601f850160051c820191505b818110156129e9578281556001016146b1565b81516001600160401b038111156146dd576146dd61347d565b6146f1816146eb8454614024565b8461467c565b602080601f831160018114614726576000841561470e5750858301515b600019600386901b1c1916600185901b1785556129e9565b600085815260208120601f198616915b8281101561475557888601518255948401946001909101908401614736565b50858210156147735787850151600019600388901b60f8161c191681555b5050505050600190811b0190555056fe4e6f756e7344414f3a3a67657444796e616d696351756f72756d506172616d7341743a20626c6f636b206e756d62657220657863656564732033322062697473a26469706673582212203d27194f160b95bf2f25018dac840393c3bd014f71918b4913b59d1cbc642ae964736f6c63430008170033", + "nonce": "0x6", + "chainId": "0x1", + "accessList": null, + "type": null + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x3234f140996918456dfdfee0ed2e8081f9b971a9c004b24b29cc4d9aa7a96e40", + "transactionType": "CREATE", + "contractName": "NounsDAOVotes", + "contractAddress": "0x3e4e4d094a73aac69ff6592cda602b76134951d6", + "function": null, + "arguments": null, + "transaction": { + "from": "0x918895f466eb3cd5fb181626f8e1b2fd8a9d5192", + "to": null, + "gas": "0x1dc81a", + "value": null, + "input": "0x611a3361003a600b82828239805160001a60731461002d57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600436106100be5760003560e01c8063b73a99c71161007b578063b73a99c714610187578063bc4cd084146101a7578063deaaa7cc146101b3578063e105d84a146101da578063f57e66d1146101fa578063fbfee8761461021a57600080fd5b8063042bc3de146100c357806306fdde03146100e057806320606b70146101155780633be8ef3f1461013c57806350de7cf614610145578063aabb220a14610167575b600080fd5b6100cd62030d4081565b6040519081526020015b60405180910390f35b610108604051806040016040528060098152602001684e6f756e732044414f60b81b81525081565b6040516100d791906115ba565b6100cd7f8cad95687ba82c2ce50e74f7b754645e5117c3a5bec8151c0726d5857980a86681565b6100cd618ca081565b81801561015157600080fd5b50610165610160366004611640565b610225565b005b81801561017357600080fd5b506101656101823660046116b7565b610271565b81801561019357600080fd5b506101656101a23660046116ec565b6102ce565b6100cd642e90edd00081565b6100cd7f150214d74d59b7d1e90c73fc22ef3d991dd0a76b046543d4d80ab92d2a50328f81565b8180156101e657600080fd5b506101656101f5366004611754565b610310565b81801561020657600080fd5b5061016561021536600461179a565b610332565b6100cd637735940081565b61026986868686868080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250889250610593915050565b505050505050565b336000805160206119de8339815191528383610291878584846000610641565b6040805193845260ff90921660208401526001600160601b03169082015260806060820181905260009082015260a00160405180910390a2505050565b336000805160206119de83398151915285856102ee898584846000610641565b86866040516103019594939291906117f2565b60405180910390a25050505050565b61032c8484846040518060200160405280600081525085610593565b50505050565b60408051808201825260098152684e6f756e732044414f60b81b60209182015281517f8cad95687ba82c2ce50e74f7b754645e5117c3a5bec8151c0726d5857980a866818301527fe1dd93b3612547b4bb7c3d429f3df8508d84f5a4f63b5e2e44340b94698e6b3b81840152466060820152306080808301919091528351808303909101815260a0820184528051908301207f150214d74d59b7d1e90c73fc22ef3d991dd0a76b046543d4d80ab92d2a50328f60c083015260e0820189905260ff8816610100808401919091528451808403909101815261012083019094528351939092019290922061190160f01b6101408401526101428301829052610162830181905290916000906101820160408051601f198184030181528282528051602091820120600080855291840180845281905260ff8a169284019290925260608301889052608083018790529092509060019060a0016020604051602081039080840390855afa1580156104ab573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b0381166105265760405162461bcd60e51b815260206004820152602a60248201527f4e6f756e7344414f3a3a63617374566f746542795369673a20696e76616c6964604482015269207369676e617475726560b01b60648201526084015b60405180910390fd5b806001600160a01b03166000805160206119de8339815191528a8a61054f8e868f8f6000610641565b6040805193845260ff90921660208401526001600160601b03169082015260806060820181905260009082015260a00160405180910390a250505050505050505050565b60005a905060006105a78733888887610641565b9050336001600160a01b03166000805160206119de833981519152878784886040516105d69493929190611842565b60405180910390a263ffffffff8316156106205760405163ffffffff841690879033907f651cc9d78606507fdcfc4f37ec37a744d612b1d8f5a73564190577c4f0edb0b690600090a45b6001600160601b038116156106385761063882610804565b50505050505050565b60008061064e87866108f2565b9050600181600a8111156106645761066461187d565b0361067c5761067587868887610afa565b915061071f565b600981600a8111156106905761069061187d565b036106c25760ff8416156106b757604051639aeea66b60e01b815260040160405180910390fd5b610675878688610ea5565b60405162461bcd60e51b815260206004820152602c60248201527f4e6f756e7344414f3a3a63617374566f7465496e7465726e616c3a20766f746960448201526b1b99c81a5cc818db1bdcd95960a21b606482015260840161051d565b6000858152600b88016020908152604080832063ffffffff808816855260149091018352928190208151808301835290548085168252640100000000900484169281019290925280518082019091528151919290918291610782918791166118a9565b63ffffffff1681526020018260200151600161079e91906118c9565b63ffffffff9081169091526000978852600b90990160209081526040808920968b168952601490960181529490962086518154979095015189166401000000000267ffffffffffffffff1990971694909816939093179490941790955550929392505050565b476000819003610812575050565b600061082348642e90edd000611022565b905060006108373a63773594008401611022565b9050600061084e618ca05a87030162030d40611022565b9050600061085e82840286611022565b604051909150600090329083908381818185875af1925050503d80600081146108a3576040519150601f19603f3d011682016040523d82523d6000602084013e6108a8565b606091505b505060408051848152821515602082015291925032917ffabef36fd46c4c3a6ad676521be5367a4dfdbf3faa68d8e826003b1752d68f4f910160405180910390a250505050505050565b600081836008015410156109545760405162461bcd60e51b8152602060048201526024808201527f4e6f756e7344414f3a3a73746174653a20696e76616c69642070726f706f73616044820152631b081a5960e21b606482015260840161051d565b6000828152600b840160205260409020600e810154610100900460ff1615610980576008915050610af4565b600e81015460ff1615610997576002915050610af4565b601181015468010000000000000000900467ffffffffffffffff1643116109c257600a915050610af4565b806009015443116109d7576000915050610af4565b80600a015443116109ec576001915050610af4565b6011810154600160801b900467ffffffffffffffff164311610a12576009915050610af4565b610a1c848261103a565b15610a2b576003915050610af4565b8060040154600003610a41576004915050610af4565b600e81015462010000900460ff1615610a5e576007915050610af4565b610a688482611073565b6001600160a01b031663c1a287e26040518163ffffffff1660e01b8152600401602060405180830381865afa158015610aa5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ac991906118e6565b8160040154610ad891906118ff565b4210610ae8576006915050610af4565b6005915050610af4565b505b92915050565b600060028260ff161115610b765760405162461bcd60e51b815260206004820152603f60248201527f4e6f756e7344414f3a3a63617374566f7465447572696e67566f74696e67506560448201527f72696f64496e7465726e616c3a20696e76616c696420766f7465207479706500606482015260840161051d565b6000848152600b8601602090815260408083206001600160a01b0387168452600f8101909252909120805460ff1615610c215760405162461bcd60e51b815260206004820152604160248201527f4e6f756e7344414f3a3a63617374566f7465447572696e67566f74696e67506560448201527f72696f64496e7465726e616c3a20766f74657220616c726561647920766f74656064820152601960fa1b608482015260a40161051d565b600a870154600983015460405163782d6fe160e01b81526000926001600160a01b03169163782d6fe191610c6d918a916004016001600160a01b03929092168252602082015260400190565b602060405180830381865afa158015610c8a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cae9190611912565b905060008560ff16600103610cdf576010890154600a85015463ffffffff90911690610cdb90439061193b565b1090505b60008115610cf457610cf18a8661103a565b90505b8660ff16600003610d2257826001600160601b031685600c0154610d1891906118ff565b600c860155610d7a565b8660ff16600103610d5057826001600160601b031685600b0154610d4691906118ff565b600b860155610d7a565b8660ff16600203610d7a57826001600160601b031685600d0154610d7491906118ff565b600d8601555b818015610d845750805b8015610da357506011850154600160801b900467ffffffffffffffff16155b8015610db65750610db48a8661103a565b155b15610e595760108a0154600a860154610de791610de29164010000000090910463ffffffff16906118ff565b6110ab565b60118601805467ffffffffffffffff60801b1916600160801b67ffffffffffffffff93841681029190911791829055875460405191909204909216825263ffffffff16907f6553d98dd06f98670b24f69f718cdf9c8ec8e1cc42fb58b9c7908731322273479060200160405180910390a25b505081546001600160601b03821662010000026dffffffffffffffffffffffff00001960ff88166101000261ffff19909316929092176001179190911617909155915050949350505050565b6000828152600b8401602090815260408083206001600160a01b0385168452600f81019092528220805460ff1615610f375760405162461bcd60e51b815260206004820152602f60248201527f4e6f756e7344414f3a3a63617374566f7465496e7465726e616c3a20766f746560448201526e1c88185b1c9958591e481d9bdd1959608a1b606482015260840161051d565b600a860154600983015460405163782d6fe160e01b81526000926001600160a01b03169163782d6fe191610f839189916004016001600160a01b03929092168252602082015260400190565b602060405180830381865afa158015610fa0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fc49190611912565b825461ff001960ff196001600160601b038416620100008102919091166dffffffffffffffffffffffff00ff1990931692909217600117168455600c85015491925061100f916118ff565b600c909301929092555090509392505050565b60008183106110315781611033565b825b9392505050565b600b810154600c820154600091908111158061106b5750825461106890859063ffffffff9081169061111816565b81105b949350505050565b601381015460009060ff1615611097575060188201546001600160a01b0316610af4565b5060098201546001600160a01b0316610af4565b600067ffffffffffffffff8211156111145760405162461bcd60e51b815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203660448201526534206269747360d01b606482015260840161051d565b5090565b6000818152600b8301602052604081206010810154820361113e57600301549050610af4565b600c8101546010820154601183015461106b92919061116490889063ffffffff16611169565b61147e565b604080516060810182526000808252602082018190529181019190915260006111aa8360405180606001604052806040815260200161199e60409139611506565b600d85015490915060008190036112015760405180606001604052806111d38760070154611536565b61ffff1681526020016111e98760070154611536565b61ffff16815260006020909101529250610af4915050565b63ffffffff8216600d860161121760018461193b565b815481106112275761122761194e565b600091825260209091206002909102015463ffffffff16116112ba57600d850161125260018361193b565b815481106112625761126261194e565b6000918252602091829020604080516060810182526002939093029091016001015461ffff8082168452620100008204169383019390935264010000000090920463ffffffff16918101919091529250610af4915050565b8163ffffffff1685600d016000815481106112d7576112d761194e565b600091825260209091206002909102015463ffffffff16111561130c5760405180606001604052806111d38760070154611536565b60008061131a60018461193b565b90505b818111156114105760006002611333848461193b565b61133d9190611964565b611347908361193b565b9050600088600d0182815481106113605761136061194e565b60009182526020918290206040805180820182526002909302909101805463ffffffff9081168452825160608101845260019092015461ffff8082168452620100008204168387015264010000000090048116928201929092529282019290925280519092508782169116036113e157602001519550610af4945050505050565b805163ffffffff808816911610156113fb57819350611409565b61140660018361193b565b92505b505061131d565b86600d0182815481106114255761142561194e565b6000918252602091829020604080516060810182526002939093029091016001015461ffff8082168452620100008204169383019390935264010000000090920463ffffffff1691810191909152979650505050505050565b6000808361148e86612710611986565b6114989190611964565b90506000620f424082856040015163ffffffff166114b69190611986565b6114c09190611964565b9050600081856000015161ffff166114d891906118ff565b905060006114ee866020015161ffff1683611022565b90506114fa818861155b565b98975050505050505050565b60008163ffffffff84111561152e5760405162461bcd60e51b815260040161051d91906115ba565b509192915050565b600061ffff8211156111145760405163555abf0160e11b815260040160405180910390fd5b600061271061156a8484611986565b6110339190611964565b6000815180845260005b8181101561159a5760208185018101518683018201520161157e565b506000602082860101526020601f19601f83011685010191505092915050565b6020815260006110336020830184611574565b803560ff811681146115de57600080fd5b919050565b60008083601f8401126115f557600080fd5b50813567ffffffffffffffff81111561160d57600080fd5b60208301915083602082850101111561162557600080fd5b9250929050565b803563ffffffff811681146115de57600080fd5b60008060008060008060a0878903121561165957600080fd5b8635955060208701359450611670604088016115cd565b9350606087013567ffffffffffffffff81111561168c57600080fd5b61169889828a016115e3565b90945092506116ab90506080880161162c565b90509295509295509295565b6000806000606084860312156116cc57600080fd5b83359250602084013591506116e3604085016115cd565b90509250925092565b60008060008060006080868803121561170457600080fd5b853594506020860135935061171b604087016115cd565b9250606086013567ffffffffffffffff81111561173757600080fd5b611743888289016115e3565b969995985093965092949392505050565b6000806000806080858703121561176a57600080fd5b8435935060208501359250611781604086016115cd565b915061178f6060860161162c565b905092959194509250565b60008060008060008060c087890312156117b357600080fd5b86359550602087013594506117ca604088016115cd565b93506117d8606088016115cd565b92506080870135915060a087013590509295509295509295565b85815260ff851660208201526001600160601b038416604082015260806060820152816080820152818360a0830137600081830160a090810191909152601f909201601f19160101949350505050565b84815260ff841660208201526001600160601b03831660408201526080606082015260006118736080830184611574565b9695505050505050565b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052601160045260246000fd5b6001600160601b03818116838216019080821115610af257610af2611893565b63ffffffff818116838216019080821115610af257610af2611893565b6000602082840312156118f857600080fd5b5051919050565b80820180821115610af457610af4611893565b60006020828403121561192457600080fd5b81516001600160601b038116811461103357600080fd5b81810381811115610af457610af4611893565b634e487b7160e01b600052603260045260246000fd5b60008261198157634e487b7160e01b600052601260045260246000fd5b500490565b8082028115828204841417610af457610af461189356fe4e6f756e7344414f3a3a67657444796e616d696351756f72756d506172616d7341743a20626c6f636b206e756d62657220657863656564732033322062697473b8e138887d0aa13bab447e82de9d5c1777041ecd21ca36ba824ff1e6c07ddda4a264697066735822122043105a1adbc23b09950f1109a24d3d90a2f0b2ecc9d47ae2033b4ca57273b9bb64736f6c63430008170033", + "nonce": "0x7", + "chainId": "0x1", + "accessList": null, + "type": null + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x7c7453c2143ccf8e68988aa6bfd0bf9f8c6eee1ba6c193090e466af34f669428", + "transactionType": "CREATE", + "contractName": "NounsDAOLogicV4", + "contractAddress": "0xa23e8a919d29d74ee24d909d80f4bc8778d656d1", + "function": null, + "arguments": null, + "transaction": { + "from": "0x918895f466eb3cd5fb181626f8e1b2fd8a9d5192", + "to": null, + "gas": "0x66a8ca", + "value": "0x0", + "input": "0x608060405234801561001057600080fd5b50615cac80620000216000396000f3fe6080604052600436106104405760003560e01c80637d17aa3a11610234578063c37522d41161012e578063da9427c4116100b6578063e48083fe1161007a578063e48083fe14610bd8578063ea3ecd0f14610d64578063f32293d214610d79578063f851a44014610d8e578063fe0d94c114610dac57610447565b8063da9427c414610c87578063da95691a14610ca7578063ddf0b00914610cc7578063e23a9a5214610ce7578063e2742e1814610d3757610447565b8063d27dd112116100fd578063d27dd11214610c01578063d33219b414610c21578063d8bff44014610c3f578063d93150be14610c5d578063da35c66414610c7257610447565b8063c37522d414610b96578063c3dd69eb14610bb8578063c82fbd0814610bd8578063cd0d9eac14610bec57610447565b806397242b8e116101bc578063aa0e23c711610180578063aa0e23c714610b07578063abb308b214610b34578063b112626314610ab1578063b58131b014610b61578063b5cd5bfa14610b7657610447565b806397242b8e14610a715780639a0dfb5314610a91578063a64e024a14610ab1578063a67d063514610ac7578063a9cf82f014610ae557610447565b806383cce0e11161020357806383cce0e1146109e457806384d1d199146109f95780638f1314b614610a1e5780638f1447d914610a3357806390f8c2f414610a5357610447565b80637d17aa3a146109725780637f5ef445146109945780637fa230bd146109af5780638136730f146109c457610447565b80633e2733341161034557806355ce73b1116102cd5780637217024c116102915780637217024c146108cb57806377388b70146108eb5780637757d18d146109205780637b3c71d31461093e5780637bdbe4d01461095e57610447565b806355ce73b1146108295780635678138814610849578063590c1f161461086957806364c0599514610889578063705cb335146108a957610447565b806344fac8f61161031457806344fac8f61461078757806347f4a077146107a757806349e857ea146107d457806353349413146107f45780635408e7f21461080957610447565b80633e273334146107055780633e4f49e61461071a5780633fde324d1461074757806340e58ee51461076757610447565b806328aa53e4116103c857806336a3b5781161039757806336a3b5781461067b57806338b1c2f6146106905780633932abb1146106b05780633b66c516146106c55780633bccf4fd146106e557610447565b806328aa53e4146105d95780632a4fa9fe146105f95780632de45f1814610619578063328dd9821461064b57610447565b806316f1b8cf1161040f57806316f1b8cf1461053757806317977c61146105575780631d28dec71461058d5780631e7b5d3a146105af578063215809ca146105c457610447565b8063013cf08b146104ad57806302a251a3146104e35780630f7b1f081461050257806314a67ea41461052257610447565b3661044757005b60003660606104a173d7c7c3c447df757a77c81fcff07f10bb22d98f4a6000368080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610dcc92505050565b80519350602001915050f35b3480156104b957600080fd5b506104cd6104c8366004613b3f565b610dfa565b6040516104da9190613b58565b60405180910390f35b3480156104ef57600080fd5b506005545b6040519081526020016104da565b34801561050e57600080fd5b506104f461051d366004613b3f565b610efe565b34801561052e57600080fd5b506006546104f4565b34801561054357600080fd5b506104f4610552366004613fa1565b610f0a565b34801561056357600080fd5b506104f4610572366004614095565b6001600160a01b03166000908152600c602052604090205490565b34801561059957600080fd5b506105ad6105a8366004613b3f565b610f27565b005b3480156105bb57600080fd5b506103e86104f4565b3480156105d057600080fd5b50611c206104f4565b3480156105e557600080fd5b506105ad6105f43660046140b2565b610f95565b34801561060557600080fd5b506104f4610614366004614174565b611408565b34801561062557600080fd5b50600a546001600160a01b03165b6040516001600160a01b0390911681526020016104da565b34801561065757600080fd5b5061066b610666366004613b3f565b611442565b6040516104da9493929190614374565b34801561068757600080fd5b506104f4611461565b34801561069c57600080fd5b506104f46106ab3660046143c1565b6114de565b3480156106bc57600080fd5b506004546104f4565b3480156106d157600080fd5b506104f46106e0366004614174565b611522565b3480156106f157600080fd5b506105ad6107003660046144a3565b61155c565b34801561071157600080fd5b506104f46115ed565b34801561072657600080fd5b5061073a610735366004613b3f565b611604565b6040516104da9190614507565b34801561075357600080fd5b506105ad610762366004614577565b611682565b34801561077357600080fd5b506105ad610782366004613b3f565b6116f2565b34801561079357600080fd5b506105ad6107a23660046145b8565b611731565b3480156107b357600080fd5b506107c76107c2366004613b3f565b611780565b6040516104da91906145e4565b3480156107e057600080fd5b506105ad6107ef366004614658565b6117a8565b34801561080057600080fd5b506016546104f4565b34801561081557600080fd5b506105ad61082436600461468d565b6117e4565b34801561083557600080fd5b506105ad6108443660046146c4565b611860565b34801561085557600080fd5b506105ad6108643660046145b8565b6118d3565b34801561087557600080fd5b506105ad61088436600461471a565b61191b565b34801561089557600080fd5b506105ad6108a43660046147b3565b61195f565b3480156108b557600080fd5b50601054600160201b900463ffffffff166104f4565b3480156108d757600080fd5b506104f46108e636600461480c565b6119d7565b3480156108f757600080fd5b50610900611a84565b604080516001600160a01b039384168152929091166020830152016104da565b34801561092c57600080fd5b506011546001600160a01b0316610633565b34801561094a57600080fd5b506105ad6109593660046147b3565b611b04565b34801561096a57600080fd5b50600a6104f4565b34801561097e57600080fd5b50601054600160401b900463ffffffff166104f4565b3480156109a057600080fd5b5060105463ffffffff166104f4565b3480156109bb57600080fd5b506104f4611b44565b3480156109d057600080fd5b506105ad6109df366004614912565b611b5b565b3480156109f057600080fd5b506007546104f4565b348015610a0557600080fd5b50601054600160601b90046001600160a01b0316610633565b348015610a2a57600080fd5b506104f4611b9d565b348015610a3f57600080fd5b506105ad610a4e366004614980565b611ba9565b348015610a5f57600080fd5b506018546001600160a01b0316610633565b348015610a7d57600080fd5b506105ad610a8c3660046149bc565b611bfd565b348015610a9d57600080fd5b506104f4610aac366004614af2565b611c97565b348015610abd57600080fd5b50620189c06104f4565b348015610ad357600080fd5b50600e546001600160a01b0316610633565b348015610af157600080fd5b50610afa611d20565b6040516104da9190614baa565b348015610b1357600080fd5b50610b27610b22366004614c06565b611dc5565b6040516104da9190614cd8565b348015610b4057600080fd5b50610b54610b4f366004613b3f565b611dd8565b6040516104da9190614d9f565b348015610b6d57600080fd5b506104f4611e84565b348015610b8257600080fd5b506105ad610b9136600461471a565b611e99565b348015610ba257600080fd5b50610bab611edd565b6040516104da9190614dad565b348015610bc457600080fd5b506105ad610bd3366004614dc0565b611f42565b348015610be457600080fd5b5060016104f4565b348015610bf857600080fd5b506104f4611f84565b348015610c0d57600080fd5b506105ad610c1c366004614658565b611fbf565b348015610c2d57600080fd5b506009546001600160a01b0316610633565b348015610c4b57600080fd5b506003546001600160a01b0316610633565b348015610c6957600080fd5b506015546104f4565b348015610c7e57600080fd5b506008546104f4565b348015610c9357600080fd5b506105ad610ca2366004614e39565b611ffb565b348015610cb357600080fd5b506104f4610cc23660046143c1565b612041565b348015610cd357600080fd5b506105ad610ce2366004613b3f565b612052565b348015610cf357600080fd5b50610d07610d02366004614f38565b612091565b6040805182511515815260208084015160ff1690820152918101516001600160601b0316908201526060016104da565b348015610d4357600080fd5b50610d57610d52366004613b3f565b61211d565b6040516104da9190614f68565b348015610d7057600080fd5b506019546104f4565b348015610d8557600080fd5b506017546104f4565b348015610d9a57600080fd5b506000546001600160a01b0316610633565b348015610db857600080fd5b506105ad610dc7366004613b3f565b612242565b6060610df18383604051806060016040528060278152602001615c1060279139612281565b90505b92915050565b610e82604051806101e001604052806000815260200160006001600160a01b03168152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160001515815260200160001515815260200160001515815260200160008152602001600081525090565b604051631257ca3b60e31b8152600060048201526024810183905273ac6eefcc699047856c07c8679e1339903bd5ffcc906392be51d8906044016101e060405180830381865af4158015610eda573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610df491906150ad565b6000610df48183612350565b6000610f1c87878787878760006119d7565b979650505050505050565b604051632cbebd3560e21b8152600060048201526024810182905273ac6eefcc699047856c07c8679e1339903bd5ffcc9063b2faf4d4906044015b60006040518083038186803b158015610f7a57600080fd5b505af4158015610f8e573d6000803e3d6000fd5b5050505050565b6009546001600160a01b031615610fbf57604051630205737f60e61b815260040160405180910390fd5b6000546001600160a01b03163314610fea57604051633057182d60e21b815260040160405180910390fd5b6001600160a01b03871661101157604051637330d04160e11b815260040160405180910390fd5b6001600160a01b0386166110385760405163d2ef0d7160e01b815260040160405180910390fd5b6040516303a8b66360e21b81528235600482015273d7c7c3c447df757a77c81fcff07f10bb22d98f4a90630ea2d98c9060240160006040518083038186803b15801561108357600080fd5b505af4158015611097573d6000803e3d6000fd5b5050604051630efd8dad60e11b81526020850135600482015273d7c7c3c447df757a77c81fcff07f10bb22d98f4a9250631dfb1b5a915060240160006040518083038186803b1580156110e957600080fd5b505af41580156110fd573d6000803e3d6000fd5b5050604080516397d048e560e01b815290850135600482015273d7c7c3c447df757a77c81fcff07f10bb22d98f4a92506397d048e5915060240160006040518083038186803b15801561114f57600080fd5b505af4158015611163573d6000803e3d6000fd5b5050600980546001600160a01b03199081166001600160a01b038c811691909117909255600a805482168b8416179055601080546001600160601b0316600160601b8b851602179055601180548216898416179055600380549091169187169190911790555073d7c7c3c447df757a77c81fcff07f10bb22d98f4a905063ec91deda6111f26020840184615186565b6112026040850160208601615186565b61121260608601604087016151a1565b6040516001600160e01b031960e086901b16815261ffff938416600482015292909116602483015263ffffffff16604482015260640160006040518083038186803b15801561126057600080fd5b505af4158015611274573d6000803e3d6000fd5b5050505073d7c7c3c447df757a77c81fcff07f10bb22d98f4a63e25607728360600160208101906112a591906151a1565b6040516001600160e01b031960e084901b16815263ffffffff91909116600482015260240160006040518083038186803b1580156112e257600080fd5b505af41580156112f6573d6000803e3d6000fd5b5050505073d7c7c3c447df757a77c81fcff07f10bb22d98f4a63e5eb5abf83608001602081019061132791906151a1565b6040516001600160e01b031960e084901b16815263ffffffff91909116600482015260240160006040518083038186803b15801561136457600080fd5b505af4158015611378573d6000803e3d6000fd5b5050505073d7c7c3c447df757a77c81fcff07f10bb22d98f4a6374b157b88360a00160208101906113a991906151a1565b6040516001600160e01b031960e084901b16815263ffffffff9190911660048201526024015b60006040518083038186803b1580156113e757600080fd5b505af41580156113fb573d6000803e3d6000fd5b5050505050505050505050565b6000610f1c604051806080016040528089815260200188815260200187815260200186815250848460006123a9909392919063ffffffff16565b60608080806114526000866124fa565b93509350935093509193509193565b6040516319244b1760e01b815260006004820181905290733d4f1ee041c31afc0fbda4f058d34544d71eb6ad906319244b17906024015b602060405180830381865af41580156114b5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114d991906151bc565b905090565b60006115186040518060800160405280888152602001878152602001868152602001858152508360008061278f909392919063ffffffff16565b9695505050505050565b6000610f1c6040518060800160405280898152602001888152602001878152602001868152508484600061278f909392919063ffffffff16565b60405163f57e66d160e01b8152600060048201526024810186905260ff8086166044830152841660648201526084810183905260a48101829052733e4e4d094a73aac69ff6592cda602b76134951d69063f57e66d19060c4015b60006040518083038186803b1580156115ce57600080fd5b505af41580156115e2573d6000803e3d6000fd5b505050505050505050565b60006114d96115fc6000612806565b600090612982565b6040516373d0ed2f60e01b8152600060048201819052602482018390529073ac6eefcc699047856c07c8679e1339903bd5ffcc906373d0ed2f90604401602060405180830381865af415801561165e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610df491906151d5565b60405163b7aa3e5760e01b815273ac6eefcc699047856c07c8679e1339903bd5ffcc9063b7aa3e57906116be906000908690869060040161521f565b60006040518083038186803b1580156116d657600080fd5b505af41580156116ea573d6000803e3d6000fd5b505050505050565b604051631e7296df60e11b8152600060048201526024810182905273ac6eefcc699047856c07c8679e1339903bd5ffcc90633ce52dbe90604401610f62565b604051637082ec2560e11b81526000600482018190526024820184905260ff831660448301526064820152733e4e4d094a73aac69ff6592cda602b76134951d69063e105d84a906084016116be565b6040805160608101825260008082526020820181905291810191909152610df460008361299c565b6040516302bbd42360e11b8152733d4f1ee041c31afc0fbda4f058d34544d71eb6ad90630577a846906116be9060009086908690600401615274565b6040516383478b4360e01b815273ac6eefcc699047856c07c8679e1339903bd5ffcc906383478b4390611828906000908a908a908a908a908a908a9060040161528e565b60006040518083038186803b15801561184057600080fd5b505af4158015611854573d6000803e3d6000fd5b50505050505050505050565b60405163575535f360e11b8152733d4f1ee041c31afc0fbda4f058d34544d71eb6ad9063aeaa6be69061189e90600090879087908790600401615309565b60006040518083038186803b1580156118b657600080fd5b505af41580156118ca573d6000803e3d6000fd5b50505050505050565b60405163555d910560e11b8152600060048201526024810183905260ff82166044820152733e4e4d094a73aac69ff6592cda602b76134951d69063aabb220a906064016116be565b604051633d43469f60e11b8152733d4f1ee041c31afc0fbda4f058d34544d71eb6ad90637a868d3e90611828906000908a908a908a908a908a908a9060040161533c565b60405163286f3e7b60e11b8152733e4e4d094a73aac69ff6592cda602b76134951d6906350de7cf6906119a1906000908890889088908890859060040161537e565b60006040518083038186803b1580156119b957600080fd5b505af41580156119cd573d6000803e3d6000fd5b5050505050505050565b60408051608081018252878152602081018790528082018690526060810185905290516320660f5360e01b815260009173ac6eefcc699047856c07c8679e1339903bd5ffcc916320660f5391611a379185918d9189908990600401615516565b602060405180830381865af4158015611a54573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a7891906151bc565b98975050505050505050565b6040516338251d8960e11b8152600060048201819052908190733d4f1ee041c31afc0fbda4f058d34544d71eb6ad9063704a3b12906024016040805180830381865af4158015611ad8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611afc919061556e565b915091509091565b60405163b73a99c760e01b8152733e4e4d094a73aac69ff6592cda602b76134951d69063b73a99c7906119a190600090889088908890889060040161559d565b60006114d9611b536000612806565b600090612cae565b60405163286f3e7b60e11b8152733e4e4d094a73aac69ff6592cda602b76134951d6906350de7cf6906115b6906000908990899089908990899060040161537e565b60006114d96000612806565b604051637082ec2560e11b8152600060048201526024810184905260ff8316604482015263ffffffff82166064820152733e4e4d094a73aac69ff6592cda602b76134951d69063e105d84a9060840161189e565b604080516080810182528781526020810187905280820186905260608101859052905163f9df1e1960e01b815273ac6eefcc699047856c07c8679e1339903bd5ffcc9163f9df1e1991611c5d916000918d918d91899089906004016155c6565b60006040518083038186803b158015611c7557600080fd5b505af4158015611c89573d6000803e3d6000fd5b505050505050505050505050565b60405163bb29607560e01b815260009073b5aa61eff82ea7b4ea6443532df15b7d4b40c3a09063bb29607590611cd59087908790879060040161562c565b602060405180830381865af4158015611cf2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d1691906151bc565b90505b9392505050565b60606000600d01805480602002602001604051908101604052809291908181526020016000905b82821015611dbc57600084815260209081902060408051808201825260028602909201805463ffffffff9081168452825160608101845260019283015461ffff80821683526201000082041682880152600160201b900490911692810192909252828401919091529083529092019101611d47565b50505050905090565b6060611a78600089898989898989612ccb565b611e0b60408051808201825260008082528251606081018452818152602081810183905293810191909152909182015290565b600d805483908110611e1f57611e1f615669565b60009182526020918290206040805180820182526002909302909101805463ffffffff9081168452825160608101845260019092015461ffff80821684526201000082041683870152600160201b900416918101919091529181019190915292915050565b60006114d9611e91611b9d565b6000906130c3565b604051633d99f84560e21b8152733d4f1ee041c31afc0fbda4f058d34544d71eb6ad9063f667e11490611828906000908a908a908a908a908a908a9060040161533c565b60606000601201805480602002602001604051908101604052809291908181526020018280548015611f3857602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311611f1a575b5050505050905090565b6040516316147f8760e31b815273ac6eefcc699047856c07c8679e1339903bd5ffcc9063b0a3fc38906115b6906000908990899089908990899060040161567f565b6040516309ea0cfb60e11b815260006004820181905290733d4f1ee041c31afc0fbda4f058d34544d71eb6ad906313d419f690602401611498565b604051636055f93560e01b8152733d4f1ee041c31afc0fbda4f058d34544d71eb6ad90636055f935906116be9060009086908690600401615274565b604051637b55bff360e01b815273ac6eefcc699047856c07c8679e1339903bd5ffcc90637b55bff3906113cf906000908b908b908b908b908b908b908b906004016156b2565b600061151886868686866000611408565b60405163179aac6b60e21b8152600060048201526024810182905273ac6eefcc699047856c07c8679e1339903bd5ffcc90635e6ab1ac90604401610f62565b604080516060808201835260008083526020808401829052838501829052845180840186528281528082018390528501829052868252600b81528482206001600160a01b0387168352600f01815290849020845192830185525460ff80821615158452610100820416918301919091526201000090046001600160601b03169281019290925290610df1565b6121c36040518061026001604052806000815260200160006001600160a01b03168152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160001515815260200160001515815260200160001515815260200160008152602001600081526020016060815260200160008152602001600081526020016000151581525090565b60405163ddb6398360e01b8152600060048201526024810183905273ac6eefcc699047856c07c8679e1339903bd5ffcc9063ddb6398390604401600060405180830381865af415801561221a573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610df491908101906157ad565b60405163370d357760e01b8152600060048201526024810182905273ac6eefcc699047856c07c8679e1339903bd5ffcc9063370d357790604401610f62565b6060833b6122e55760405162461bcd60e51b815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f6044820152651b9d1c9858dd60d21b60648201526084015b60405180910390fd5b600080856001600160a01b0316856040516123009190615905565b600060405180830381855af49150503d806000811461233b576040519150601f19603f3d011682016040523d82523d6000602084013e612340565b606091505b50915091506115188282866130d3565b6000818152600b8301602052604081206010810154820361237657600301549050610df4565b600c810154601082015460118301546123a192919061239c90889063ffffffff1661299c565b61310c565b949350505050565b6000806123b586612806565b600a87015490915060009061245c9088906001600160a01b031663782d6fe1336123e0600143615937565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401602060405180830381865afa158015612429573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061244d919061594a565b6001600160601b031684613188565b9050612467866131b6565b612471873361324d565b6008870154612481906001615973565b600888018190556000906124949061330a565b905060006124a6898385878c8b613373565b336000908152600c8b016020908152604080832063ffffffff87169055805192835290820190529091506124e89082906124e08c88612982565b8b8b8b61353a565b5063ffffffff16979650505050505050565b606080606080600086600b0160008781526020019081526020016000209050806005018160060182600701836008018380548060200260200160405190810160405280929190818152602001828054801561257e57602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311612560575b50505050509350828054806020026020016040519081016040528092919081815260200182805480156125d057602002820191906000526020600020905b8154815260200190600101908083116125bc575b5050505050925081805480602002602001604051908101604052809291908181526020016000905b828210156126a457838290600052602060002001805461261790615986565b80601f016020809104026020016040519081016040528092919081815260200182805461264390615986565b80156126905780601f1061266557610100808354040283529160200191612690565b820191906000526020600020905b81548152906001019060200180831161267357829003601f168201915b5050505050815260200190600101906125f8565b50505050915080805480602002602001604051908101604052809291908181526020016000905b828210156127775783829060005260206000200180546126ea90615986565b80601f016020809104026020016040519081016040528092919081815260200182805461271690615986565b80156127635780601f1061273857610100808354040283529160200191612763565b820191906000526020600020905b81548152906001019060200180831161274657829003601f168201915b5050505050815260200190600101906126cb565b50505050905094509450945094505092959194509250565b60008061279e868686866123a9565b6000818152600b880160205260409081902060138101805460ff191660011790559051919250907f9fb4e5204ac554428e5c744568b78732c229c76c0b5eaebdca7171c41366f6af906127f49084815260200190565b60405180910390a15095945050505050565b600081601001600c9054906101000a90046001600160a01b03166001600160a01b0316639b3c1e226040518163ffffffff1660e01b8152600401602060405180830381865afa15801561285d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061288191906151bc565b600a83015460098401546040516370a0823160e01b81526001600160a01b0391821660048201529116906370a0823190602401602060405180830381865afa1580156128d1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128f591906151bc565b83600a0160009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561294a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061296e91906151bc565b6129789190615937565b610df49190615937565b6000610df1612991844361299c565b5161ffff1683613614565b604080516060810182526000808252602082018190529181019190915260006129dd83604051806060016040528060408152602001615c376040913961362d565b600d8501549091506000819003612a34576040518060600160405280612a06876007015461365d565b61ffff168152602001612a1c876007015461365d565b61ffff16815260006020909101529250610df4915050565b63ffffffff8216600d8601612a4a600184615937565b81548110612a5a57612a5a615669565b600091825260209091206002909102015463ffffffff1611612aec57600d8501612a85600183615937565b81548110612a9557612a95615669565b6000918252602091829020604080516060810182526002939093029091016001015461ffff80821684526201000082041693830193909352600160201b90920463ffffffff16918101919091529250610df4915050565b8163ffffffff1685600d01600081548110612b0957612b09615669565b600091825260209091206002909102015463ffffffff161115612b3e576040518060600160405280612a06876007015461365d565b600080612b4c600184615937565b90505b81811115612c415760006002612b658484615937565b612b6f91906159c0565b612b799083615937565b9050600088600d018281548110612b9257612b92615669565b60009182526020918290206040805180820182526002909302909101805463ffffffff9081168452825160608101845260019092015461ffff80821684526201000082041683870152600160201b9004811692820192909252928201929092528051909250878216911603612c1257602001519550610df4945050505050565b805163ffffffff80881691161015612c2c57819350612c3a565b612c37600183615937565b92505b5050612b4f565b86600d018281548110612c5657612c56615669565b6000918252602091829020604080516060810182526002939093029091016001015461ffff80821684526201000082041693830193909352600160201b90920463ffffffff1691810191909152979650505050505050565b6000610df1612cbd844361299c565b6020015161ffff1683613614565b606087871015612d275760405162461bcd60e51b815260206004820152602160248201527f6c61737450726f706f73616c4964203e3d20666972737450726f706f73616c496044820152601960fa1b60648201526084016122dc565b6000612d338989615937565b612d3e906001615973565b90506000816001600160401b03811115612d5a57612d5a613c1e565b604051908082528060200260200182016040528015612de057816020015b612dcd60405180610120016040528060008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600063ffffffff168152602001606081525090565b815260200190600190039081612d785790505b509050600080612e03604051806040016040528060008152602001600081525090565b8c5b8c81116130b0578e600b01600082815260200190815260200160002093508a8015612e345750600e84015460ff165b6130a057600a84015482526011840154600160801b90046001600160401b031660208301528915612ed5576000612e7383600001518460200151613682565b9050804311612ed35760405162461bcd60e51b815260206004820152602660248201527f616c6c2070726f706f73616c73206d75737420626520646f6e65207769746820604482015265766f74696e6760d01b60648201526084016122dc565b505b600084600b015490506000856010015490506127108e61ffff1682612efa91906159e2565b612f0491906159c0565b821015612f125750506130a0565b60008a6001600160401b03811115612f2c57612f2c613c1e565b604051908082528060200260200182016040528015612f7157816020015b6040805180820190915260008082526020820152815260200190600190039081612f4a5790505b50905060005b8b81101561300b578760140160008e8e84818110612f9757612f97615669565b9050602002016020810190612fac91906151a1565b63ffffffff908116825260208083019390935260409182016000208251808401909352548082168352600160201b900416918101919091528251839083908110612ff857612ff8615669565b6020908102919091010152600101612f77565b5060408051610120810182528651815260208088015190820152908101849052600c8801546060820152600d880154608082015260a08101839052601188015463ffffffff600160201b91829004811660c08401528954919091041660e08201526101008101829052888761307f816159f9565b98508151811061309157613091615669565b60200260200101819052505050505b6130a9816159f9565b9050612e05565b50508252509a9950505050505050505050565b6000610df1836006015483613614565b606083156130e2575081611d19565b8251156130f25782518084602001fd5b8160405162461bcd60e51b81526004016122dc9190615a12565b6000808361311c866127106159e2565b61312691906159c0565b90506000620f424082856040015163ffffffff1661314491906159e2565b61314e91906159c0565b9050600081856000015161ffff166131669190615973565b9050600061317c866020015161ffff1683613698565b9050611a788188613614565b600061319484836130c3565b9050808311611d195760405163ead8241560e01b815260040160405180910390fd5b6020810151518151511415806131d3575060408101515181515114155b806131e5575060608101515181515114155b156132035760405163ccb0ce3f60e01b815260040160405180910390fd5b80515160000361322657604051630f24cd7360e01b815260040160405180910390fd5b805151600a101561324a576040516308e3b1eb60e11b815260040160405180910390fd5b50565b6001600160a01b0381166000908152600c83016020526040902054801561330557600061327a84836136a7565b9050600981600a811115613290576132906144f1565b14806132ad5750600181600a8111156132ab576132ab6144f1565b145b806132c95750600081600a8111156132c7576132c76144f1565b145b806132e55750600a81600a8111156132e3576132e36144f1565b145b15613303576040516306bee79560e01b815260040160405180910390fd5b505b505050565b600063ffffffff82111561336f5760405162461bcd60e51b815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203360448201526532206269747360d01b60648201526084016122dc565b5090565b6010860154600090819061339d9061339890600160401b900463ffffffff1643615973565b6138a0565b905060008860040154826001600160401b03166133ba9190615973565b905060008960050154826133ce9190615973565b63ffffffff808b166000818152600b8e01602090815260409091208054938a16600160201b0267ffffffffffffffff199094169092179290921781556001810180546001600160a01b03191633179055600281018b90558851805191975092935061343f9260058801920190613976565b50602080870151805161345892600688019201906139d7565b5060408601518051613474916007870191602090910190613a12565b5060608601518051613490916008870191602090910190613a64565b5060098401829055600a8401819055601084018790556134af4361330a565b60118501805463ffffffff191663ffffffff929092169190911790556134d44261330a565b6011850180546001600160401b03909516600160401b026fffffffffffffffff00000000000000001963ffffffff93909316600160201b02929092166fffffffffffffffffffffffff000000001990951694909417179092555090979650505050505050565b855483516020850151604080870151606088015160098c0154600a8d015493517f7d84a6263ae0d98d3329bd7b46bb4e8d6f98cd35a7adb45c274c8b7fd5ebd5e09761359d9763ffffffff90911696339691959094909390929091908c90615a25565b60405180910390a185546011870154600288015460405163ffffffff808616947fd9d12651716feaac10e3b79bd2960ad42ebfd84969b71a2e226ec99972a8712e946136049491909216928b926001600160401b03600160401b9091041691908b90615ac3565b60405180910390a2505050505050565b600061271061362384846159e2565b610df191906159c0565b60008163ffffffff8411156136555760405162461bcd60e51b81526004016122dc9190615a12565b509192915050565b600061ffff82111561336f5760405163555abf0160e11b815260040160405180910390fd5b60008183116136915781610df1565b5090919050565b60008183106136915781610df1565b600081836008015410156137095760405162461bcd60e51b8152602060048201526024808201527f4e6f756e7344414f3a3a73746174653a20696e76616c69642070726f706f73616044820152631b081a5960e21b60648201526084016122dc565b6000828152600b840160205260409020600e810154610100900460ff1615613735576008915050610df4565b600e81015460ff161561374c576002915050610df4565b6011810154600160401b90046001600160401b0316431161377157600a915050610df4565b80600901544311613786576000915050610df4565b80600a0154431161379b576001915050610df4565b6011810154600160801b90046001600160401b031643116137c0576009915050610df4565b6137ca8482613908565b156137d9576003915050610df4565b80600401546000036137ef576004915050610df4565b600e81015462010000900460ff161561380c576007915050610df4565b613816848261393e565b6001600160a01b031663c1a287e26040518163ffffffff1660e01b8152600401602060405180830381865afa158015613853573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061387791906151bc565b81600401546138869190615973565b4210613896576006915050610df4565b6005915050610df4565b60006001600160401b0382111561336f5760405162461bcd60e51b815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203660448201526534206269747360d01b60648201526084016122dc565b600b810154600c82015460009190811115806123a15750825461393690859063ffffffff9081169061235016565b119392505050565b601381015460009060ff1615613962575060188201546001600160a01b0316610df4565b5060098201546001600160a01b0316610df4565b8280548282559060005260206000209081019282156139cb579160200282015b828111156139cb57825182546001600160a01b0319166001600160a01b03909116178255602090920191600190910190613996565b5061336f929150613ab6565b8280548282559060005260206000209081019282156139cb579160200282015b828111156139cb5782518255916020019190600101906139f7565b828054828255906000526020600020908101928215613a58579160200282015b82811115613a585782518290613a489082615b50565b5091602001919060010190613a32565b5061336f929150613acb565b828054828255906000526020600020908101928215613aaa579160200282015b82811115613aaa5782518290613a9a9082615b50565b5091602001919060010190613a84565b5061336f929150613ae8565b5b8082111561336f5760008155600101613ab7565b8082111561336f576000613adf8282613b05565b50600101613acb565b8082111561336f576000613afc8282613b05565b50600101613ae8565b508054613b1190615986565b6000825580601f10613b21575050565b601f01602090049060005260206000209081019061324a9190613ab6565b600060208284031215613b5157600080fd5b5035919050565b815181526020808301516101e0830191613b7c908401826001600160a01b03169052565b5060408301516040830152606083015160608301526080830151608083015260a083015160a083015260c083015160c083015260e083015160e083015261010080840151818401525061012080840151818401525061014080840151613be58285018215159052565b505061016083810151151590830152610180808401511515908301526101a080840151908301526101c092830151929091019190915290565b634e487b7160e01b600052604160045260246000fd5b604051606081016001600160401b0381118282101715613c5657613c56613c1e565b60405290565b6040516101e081016001600160401b0381118282101715613c5657613c56613c1e565b60405161026081016001600160401b0381118282101715613c5657613c56613c1e565b604051601f8201601f191681016001600160401b0381118282101715613cca57613cca613c1e565b604052919050565b60006001600160401b03821115613ceb57613ceb613c1e565b5060051b60200190565b600082601f830112613d0657600080fd5b81356001600160401b03811115613d1f57613d1f613c1e565b613d32601f8201601f1916602001613ca2565b818152846020838601011115613d4757600080fd5b816020850160208301376000918101602001919091529392505050565b6001600160a01b038116811461324a57600080fd5b600082601f830112613d8a57600080fd5b81356020613d9f613d9a83613cd2565b613ca2565b82815260059290921b84018101918181019086841115613dbe57600080fd5b8286015b84811015613e505780356001600160401b0380821115613de25760008081fd5b908801906060828b03601f1901811315613dfc5760008081fd5b613e04613c34565b8784013583811115613e165760008081fd5b613e248d8a83880101613cf5565b8252506040925082840135613e3881613d64565b81890152920135908201528352918301918301613dc2565b509695505050505050565b600082601f830112613e6c57600080fd5b81356020613e7c613d9a83613cd2565b8083825260208201915060208460051b870101935086841115613e9e57600080fd5b602086015b84811015613e50578035613eb681613d64565b8352918301918301613ea3565b600082601f830112613ed457600080fd5b81356020613ee4613d9a83613cd2565b8083825260208201915060208460051b870101935086841115613f0657600080fd5b602086015b84811015613e505780358352918301918301613f0b565b600082601f830112613f3357600080fd5b81356020613f43613d9a83613cd2565b82815260059290921b84018101918181019086841115613f6257600080fd5b8286015b84811015613e505780356001600160401b03811115613f855760008081fd5b613f938986838b0101613cf5565b845250918301918301613f66565b60008060008060008060c08789031215613fba57600080fd5b86356001600160401b0380821115613fd157600080fd5b613fdd8a838b01613d79565b97506020890135915080821115613ff357600080fd5b613fff8a838b01613e5b565b9650604089013591508082111561401557600080fd5b6140218a838b01613ec3565b9550606089013591508082111561403757600080fd5b6140438a838b01613f22565b9450608089013591508082111561405957600080fd5b6140658a838b01613f22565b935060a089013591508082111561407b57600080fd5b5061408889828a01613cf5565b9150509295509295509295565b6000602082840312156140a757600080fd5b8135611d1981613d64565b60008060008060008060008789036101c08112156140cf57600080fd5b88356140da81613d64565b975060208901356140ea81613d64565b965060408901356140fa81613d64565b9550606089013561410a81613d64565b9450608089013561411a81613d64565b935060c0609f198201121561412e57600080fd5b60a089019250606061015f198201121561414757600080fd5b506101608801905092959891949750929550565b803563ffffffff8116811461416f57600080fd5b919050565b60008060008060008060c0878903121561418d57600080fd5b86356001600160401b03808211156141a457600080fd5b6141b08a838b01613e5b565b975060208901359150808211156141c657600080fd5b6141d28a838b01613ec3565b965060408901359150808211156141e857600080fd5b6141f48a838b01613f22565b9550606089013591508082111561420a57600080fd5b6142168a838b01613f22565b9450608089013591508082111561422c57600080fd5b5061423989828a01613cf5565b92505061424860a0880161415b565b90509295509295509295565b60008151808452602080850194506020840160005b8381101561428e5781516001600160a01b031687529582019590820190600101614269565b509495945050505050565b60008151808452602080850194506020840160005b8381101561428e578151875295820195908201906001016142ae565b60005b838110156142e55781810151838201526020016142cd565b50506000910152565b600081518084526143068160208601602086016142ca565b601f01601f19169290920160200192915050565b60008282518085526020808601955060208260051b8401016020860160005b8481101561436757601f198684030189526143558383516142ee565b98840198925090830190600101614339565b5090979650505050505050565b6080815260006143876080830187614254565b82810360208401526143998187614299565b905082810360408401526143ad818661431a565b90508281036060840152610f1c818561431a565b600080600080600060a086880312156143d957600080fd5b85356001600160401b03808211156143f057600080fd5b6143fc89838a01613e5b565b9650602088013591508082111561441257600080fd5b61441e89838a01613ec3565b9550604088013591508082111561443457600080fd5b61444089838a01613f22565b9450606088013591508082111561445657600080fd5b61446289838a01613f22565b9350608088013591508082111561447857600080fd5b5061448588828901613cf5565b9150509295509295909350565b803560ff8116811461416f57600080fd5b600080600080600060a086880312156144bb57600080fd5b853594506144cb60208701614492565b93506144d960408701614492565b94979396509394606081013594506080013592915050565b634e487b7160e01b600052602160045260246000fd5b60208101600b831061452957634e487b7160e01b600052602160045260246000fd5b91905290565b60008083601f84011261454157600080fd5b5081356001600160401b0381111561455857600080fd5b60208301915083602082850101111561457057600080fd5b9250929050565b6000806020838503121561458a57600080fd5b82356001600160401b038111156145a057600080fd5b6145ac8582860161452f565b90969095509350505050565b600080604083850312156145cb57600080fd5b823591506145db60208401614492565b90509250929050565b815161ffff90811682526020808401519091169082015260408083015163ffffffff169082015260608101610df4565b60008083601f84011261462657600080fd5b5081356001600160401b0381111561463d57600080fd5b6020830191508360208260051b850101111561457057600080fd5b6000806020838503121561466b57600080fd5b82356001600160401b0381111561468157600080fd5b6145ac85828601614614565b60008060008060008060c087890312156146a657600080fd5b8635955060208701356001600160401b0380821115613ff357600080fd5b6000806000604084860312156146d957600080fd5b83356001600160401b038111156146ef57600080fd5b6146fb86828701614614565b909450925050602084013561470f81613d64565b809150509250925092565b6000806000806000806060878903121561473357600080fd5b86356001600160401b038082111561474a57600080fd5b6147568a838b01614614565b9098509650602089013591508082111561476f57600080fd5b61477b8a838b01614614565b9096509450604089013591508082111561479457600080fd5b506147a189828a0161452f565b979a9699509497509295939492505050565b600080600080606085870312156147c957600080fd5b843593506147d960208601614492565b925060408501356001600160401b038111156147f457600080fd5b6148008782880161452f565b95989497509550505050565b600080600080600080600060e0888a03121561482757600080fd5b87356001600160401b038082111561483e57600080fd5b61484a8b838c01613d79565b985060208a013591508082111561486057600080fd5b61486c8b838c01613e5b565b975060408a013591508082111561488257600080fd5b61488e8b838c01613ec3565b965060608a01359150808211156148a457600080fd5b6148b08b838c01613f22565b955060808a01359150808211156148c657600080fd5b6148d28b838c01613f22565b945060a08a01359150808211156148e857600080fd5b506148f58a828b01613cf5565b92505061490460c0890161415b565b905092959891949750929550565b60008060008060006080868803121561492a57600080fd5b8535945061493a60208701614492565b935060408601356001600160401b0381111561495557600080fd5b6149618882890161452f565b909450925061497490506060870161415b565b90509295509295909350565b60008060006060848603121561499557600080fd5b833592506149a560208501614492565b91506149b36040850161415b565b90509250925092565b600080600080600080600080610100898b0312156149d957600080fd5b8835975060208901356001600160401b03808211156149f757600080fd5b614a038c838d01613d79565b985060408b0135915080821115614a1957600080fd5b614a258c838d01613e5b565b975060608b0135915080821115614a3b57600080fd5b614a478c838d01613ec3565b965060808b0135915080821115614a5d57600080fd5b614a698c838d01613f22565b955060a08b0135915080821115614a7f57600080fd5b614a8b8c838d01613f22565b945060c08b0135915080821115614aa157600080fd5b614aad8c838d01613cf5565b935060e08b0135915080821115614ac357600080fd5b50614ad08b828c01613cf5565b9150509295985092959890939650565b803561ffff8116811461416f57600080fd5b600080600083850360a0811215614b0857600080fd5b84359350602085013592506060603f1982011215614b2557600080fd5b50614b2e613c34565b614b3a60408601614ae0565b8152614b4860608601614ae0565b6020820152614b596080860161415b565b6040820152809150509250925092565b63ffffffff81511682526020810151613305602084018261ffff8082511683528060208301511660208401525063ffffffff60408201511660408301525050565b6020808252825182820181905260009190848201906040850190845b81811015614bec57614bd9838551614b69565b9284019260809290920191600101614bc6565b50909695505050505050565b801515811461324a57600080fd5b600080600080600080600060c0888a031215614c2157600080fd5b8735965060208801359550614c3860408901614ae0565b94506060880135614c4881614bf8565b93506080880135614c5881614bf8565b925060a08801356001600160401b03811115614c7357600080fd5b614c7f8a828b01614614565b989b979a50959850939692959293505050565b60008151808452602080850194506020840160005b8381101561428e578151805163ffffffff908116895290840151168388015260409096019590820190600101614ca7565b600060208083018184528085518083526040925060408601915060408160051b87010184880160005b83811015614d9157888303603f1901855281518051845287810151888501528681015187850152606080820151908501526080808201519085015260a0808201519085015260c0808201519085015260e08082015163ffffffff16908501526101009081015161012091850182905290614d7d81860183614c92565b968901969450505090860190600101614d01565b509098975050505050505050565b60808101610df48284614b69565b602081526000610df16020830184614254565b600080600080600060608688031215614dd857600080fd5b8535945060208601356001600160401b0380821115614df657600080fd5b614e0289838a0161452f565b90965094506040880135915080821115614e1b57600080fd5b50614e288882890161452f565b969995985093965092949392505050565b600080600080600080600060e0888a031215614e5457600080fd5b8735965060208801356001600160401b0380821115614e7257600080fd5b614e7e8b838c01613e5b565b975060408a0135915080821115614e9457600080fd5b614ea08b838c01613ec3565b965060608a0135915080821115614eb657600080fd5b614ec28b838c01613f22565b955060808a0135915080821115614ed857600080fd5b614ee48b838c01613f22565b945060a08a0135915080821115614efa57600080fd5b614f068b838c01613cf5565b935060c08a0135915080821115614f1c57600080fd5b50614f298a828b01613cf5565b91505092959891949750929550565b60008060408385031215614f4b57600080fd5b823591506020830135614f5d81613d64565b809150509250929050565b602081528151602082015260006020830151614f8f60408401826001600160a01b03169052565b506040830151606083015260608301516080830152608083015160a083015260a083015160c083015260c083015160e083015260e08301516101008181850152808501519150506101208181850152808501519150506101408181850152808501519150506101606150048185018315159052565b84015190506101806150198482018315159052565b84015190506101a061502e8482018315159052565b8401516101c0848101919091528401516101e08085019190915284015161026061020080860182905291925090615069610280860184614254565b9086015161022086810191909152860151610240808701919091529095015115159301929092525090919050565b805161416f81613d64565b805161416f81614bf8565b60006101e082840312156150c057600080fd5b6150c8613c5c565b825181526150d860208401615097565b602082015260408301516040820152606083015160608201526080830151608082015260a083015160a082015260c083015160c082015260e083015160e082015261010080840151818301525061012080840151818301525061014061513f8185016150a2565b908201526101606151518482016150a2565b908201526101806151638482016150a2565b908201526101a083810151908201526101c0928301519281019290925250919050565b60006020828403121561519857600080fd5b610df182614ae0565b6000602082840312156151b357600080fd5b610df18261415b565b6000602082840312156151ce57600080fd5b5051919050565b6000602082840312156151e757600080fd5b8151600b8110611d1957600080fd5b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b8381526040602082015260006152396040830184866151f6565b95945050505050565b81835260006001600160fb1b0383111561525b57600080fd5b8260051b80836020870137939093016020019392505050565b838152604060208201526000615239604083018486615242565b87815286602082015260e0604082015260006152ad60e0830188614254565b82810360608401526152bf8188614299565b905082810360808401526152d3818761431a565b905082810360a08401526152e7818661431a565b905082810360c08401526152fb81856142ee565b9a9950505050505050505050565b848152606060208201526000615323606083018587615242565b905060018060a01b038316604083015295945050505050565b87815260806020820152600061535660808301888a615242565b8281036040840152615369818789615242565b905082810360608401526152fb8185876151f6565b86815285602082015260ff8516604082015260a0606082015260006153a760a0830185876151f6565b905063ffffffff83166080830152979650505050505050565b600082825180855260208086019550808260051b84010181860160005b8481101561436757601f19868403018952815160608151818652615403828701826142ee565b838801516001600160a01b0316878901526040938401519390960192909252505097830197908301906001016153dd565b60008282518085526020808601955060208260051b8401016020860160005b8481101561436757601f1986840301895261546f8383516142ee565b98840198925090830190600101615453565b8051608080845281519084018190526000916020919082019060a0860190845b818110156154c65783516001600160a01b0316835292840192918401916001016154a1565b50506020850151925085810360208701526154e18184614299565b92505050604083015184820360408601526154fc8282615434565b915050606083015184820360608601526152398282615434565b85815260a06020820152600061552f60a08301876153c0565b82810360408401526155418187615481565b9050828103606084015261555581866142ee565b91505063ffffffff831660808301529695505050505050565b6000806040838503121561558157600080fd5b825161558c81613d64565b6020840151909250614f5d81613d64565b85815284602082015260ff84166040820152608060608201526000610f1c6080830184866151f6565b86815285602082015260c0604082015260006155e560c08301876153c0565b82810360608401526155f78187615481565b9050828103608084015261560b81866142ee565b905082810360a084015261561f81856142ee565b9998505050505050505050565b8381526020808201849052825161ffff9081166040808501919091529184015116606083015282015163ffffffff16608082015260a081016123a1565b634e487b7160e01b600052603260045260246000fd5b86815285602082015260806040820152600061569f6080830186886151f6565b828103606084015261561f8185876151f6565b60006101008a83528960208401528060408401526156d28184018a614254565b905082810360608401526156e68189614299565b905082810360808401526156fa818861431a565b905082810360a084015261570e818761431a565b905082810360c084015261572281866142ee565b905082810360e084015261573681856142ee565b9b9a5050505050505050505050565b600082601f83011261575657600080fd5b81516020615766613d9a83613cd2565b8083825260208201915060208460051b87010193508684111561578857600080fd5b602086015b84811015613e505780516157a081613d64565b835291830191830161578d565b6000602082840312156157bf57600080fd5b81516001600160401b03808211156157d657600080fd5b9083019061026082860312156157eb57600080fd5b6157f3613c7f565b8251815261580360208401615097565b602082015260408301516040820152606083015160608201526080830151608082015260a083015160a082015260c083015160c082015260e083015160e082015261010080840151818301525061012080840151818301525061014061586a8185016150a2565b9082015261016061587c8482016150a2565b9082015261018061588e8482016150a2565b908201526101a083810151908201526101c080840151908201526101e080840151838111156158bc57600080fd5b6158c888828701615745565b91830191909152506102008381015190820152610220808401519082015261024091506158f68284016150a2565b91810191909152949350505050565b600082516159178184602087016142ca565b9190910192915050565b634e487b7160e01b600052601160045260246000fd5b81810381811115610df457610df4615921565b60006020828403121561595c57600080fd5b81516001600160601b0381168114611d1957600080fd5b80820180821115610df457610df4615921565b600181811c9082168061599a57607f821691505b6020821081036159ba57634e487b7160e01b600052602260045260246000fd5b50919050565b6000826159dd57634e487b7160e01b600052601260045260246000fd5b500490565b8082028115828204841417610df457610df4615921565b600060018201615a0b57615a0b615921565b5060010190565b602081526000610df160208301846142ee565b63ffffffff8a1681526001600160a01b038916602082015261012060408201819052600090615a568382018b614254565b90508281036060840152615a6a818a614299565b90508281036080840152615a7e818961431a565b905082810360a0840152615a92818861431a565b90508560c08401528460e0840152828103610100840152615ab381856142ee565b9c9b505050505050505050505050565b63ffffffff8616815260a060208201526000615ae260a0830187614254565b6001600160401b0395909516604083015250606081019290925260809091015292915050565b601f821115613305576000816000526020600020601f850160051c81016020861015615b315750805b601f850160051c820191505b818110156116ea57828155600101615b3d565b81516001600160401b03811115615b6957615b69613c1e565b615b7d81615b778454615986565b84615b08565b602080601f831160018114615bb25760008415615b9a5750858301515b600019600386901b1c1916600185901b1785556116ea565b600085815260208120601f198616915b82811015615be157888601518255948401946001909101908401615bc2565b5085821015615bff5787850151600019600388901b60f8161c191681555b5050505050600190811b0190555056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c65644e6f756e7344414f3a3a67657444796e616d696351756f72756d506172616d7341743a20626c6f636b206e756d62657220657863656564732033322062697473a26469706673582212209727ca74986184ed031177b5021a46512e6f96c4c604da0c453d87c2106b183b64736f6c63430008170033", + "nonce": "0x8", + "chainId": "0x1", + "accessList": null, + "type": null + }, + "additionalContracts": [], + "isFixedGasLimit": false + } + ], + "receipts": [ + { + "status": "0x1", + "cumulativeGasUsed": "0x9b6fd2", + "logs": [], + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "type": "0x2", + "transactionHash": "0xf5bbdf994c5c451133efb990bcde2544003a5bdd3c924877db95a14b97ab0982", + "transactionIndex": "0x74", + "blockHash": "0x2fb5db1009d76ea4039687fe481e262087e33cd13023aed87dc5da80c1af47a3", + "blockNumber": "0x12cdc66", + "gasUsed": "0x1e623e", + "effectiveGasPrice": "0x2180d294f", + "from": "0x918895f466eb3cd5fb181626f8e1b2fd8a9d5192", + "to": null, + "contractAddress": "0xd7c7c3c447df757a77c81fcff07f10bb22d98f4a" + }, + { + "status": "0x1", + "cumulativeGasUsed": "0x9e5709", + "logs": [], + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "type": "0x2", + "transactionHash": "0x89857e7b83a9aa57ade9d740ec6de5e57302eb3510327110e00e0b3b18622589", + "transactionIndex": "0x75", + "blockHash": "0x2fb5db1009d76ea4039687fe481e262087e33cd13023aed87dc5da80c1af47a3", + "blockNumber": "0x12cdc66", + "gasUsed": "0x2e737", + "effectiveGasPrice": "0x2180d294f", + "from": "0x918895f466eb3cd5fb181626f8e1b2fd8a9d5192", + "to": null, + "contractAddress": "0xb5aa61eff82ea7b4ea6443532df15b7d4b40c3a0" + }, + { + "status": "0x1", + "cumulativeGasUsed": "0xaf41c2", + "logs": [], + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "type": "0x2", + "transactionHash": "0x8f40d8b469c009bde3cb810314babc483ea3e47073180ac4e43917424325f7da", + "transactionIndex": "0x76", + "blockHash": "0x2fb5db1009d76ea4039687fe481e262087e33cd13023aed87dc5da80c1af47a3", + "blockNumber": "0x12cdc66", + "gasUsed": "0x10eab9", + "effectiveGasPrice": "0x2180d294f", + "from": "0x918895f466eb3cd5fb181626f8e1b2fd8a9d5192", + "to": null, + "contractAddress": "0x3d4f1ee041c31afc0fbda4f058d34544d71eb6ad" + }, + { + "status": "0x1", + "cumulativeGasUsed": "0xeccc07", + "logs": [], + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "type": "0x2", + "transactionHash": "0xa603f6aebe14018d59b50528a7c8fa404c310e7a23e016e114a33fadfe838f2a", + "transactionIndex": "0x77", + "blockHash": "0x2fb5db1009d76ea4039687fe481e262087e33cd13023aed87dc5da80c1af47a3", + "blockNumber": "0x12cdc66", + "gasUsed": "0x3d8a45", + "effectiveGasPrice": "0x2180d294f", + "from": "0x918895f466eb3cd5fb181626f8e1b2fd8a9d5192", + "to": null, + "contractAddress": "0xac6eefcc699047856c07c8679e1339903bd5ffcc" + }, + { + "status": "0x1", + "cumulativeGasUsed": "0x103b661", + "logs": [], + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "type": "0x2", + "transactionHash": "0x3234f140996918456dfdfee0ed2e8081f9b971a9c004b24b29cc4d9aa7a96e40", + "transactionIndex": "0x78", + "blockHash": "0x2fb5db1009d76ea4039687fe481e262087e33cd13023aed87dc5da80c1af47a3", + "blockNumber": "0x12cdc66", + "gasUsed": "0x16ea5a", + "effectiveGasPrice": "0x2180d294f", + "from": "0x918895f466eb3cd5fb181626f8e1b2fd8a9d5192", + "to": null, + "contractAddress": "0x3e4e4d094a73aac69ff6592cda602b76134951d6" + }, + { + "status": "0x1", + "cumulativeGasUsed": "0x152b42d", + "logs": [], + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "type": "0x2", + "transactionHash": "0x7c7453c2143ccf8e68988aa6bfd0bf9f8c6eee1ba6c193090e466af34f669428", + "transactionIndex": "0x79", + "blockHash": "0x2fb5db1009d76ea4039687fe481e262087e33cd13023aed87dc5da80c1af47a3", + "blockNumber": "0x12cdc66", + "gasUsed": "0x4efdcc", + "effectiveGasPrice": "0x2180d294f", + "from": "0x918895f466eb3cd5fb181626f8e1b2fd8a9d5192", + "to": null, + "contractAddress": "0xa23e8a919d29d74ee24d909d80f4bc8778d656d1" + } + ], + "libraries": [ + "contracts/governance/NounsDAOAdmin.sol:NounsDAOAdmin:0xd7c7c3c447Df757a77C81FcFf07f10bB22d98f4a", + "contracts/governance/NounsDAODynamicQuorum.sol:NounsDAODynamicQuorum:0xB5Aa61EfF82Ea7B4ea6443532dF15B7d4B40C3A0", + "contracts/governance/NounsDAOProposals.sol:NounsDAOProposals:0xac6eefcC699047856c07c8679e1339903bd5ffCC", + "contracts/governance/NounsDAOVotes.sol:NounsDAOVotes:0x3e4e4D094a73AAC69Ff6592CDa602B76134951d6", + "contracts/governance/fork/NounsDAOFork.sol:NounsDAOFork:0x3d4F1EE041C31aFc0FBda4f058D34544d71EB6aD" + ], + "pending": [], + "returns": { + "daoLogic": { + "internal_type": "contract NounsDAOLogicV4", + "value": "0xA23e8A919D29d74Ee24d909D80f4bC8778d656d1" + } + }, + "timestamp": 1713864921, + "chain": 1, + "commit": "82b8d911" +} \ No newline at end of file diff --git a/packages/nouns-contracts/broadcast/DeployDAOLogicOptimized.s.sol/11155111/run-1713864124.json b/packages/nouns-contracts/broadcast/DeployDAOLogicOptimized.s.sol/11155111/run-1713864124.json new file mode 100644 index 0000000000..c7e6fae0cc --- /dev/null +++ b/packages/nouns-contracts/broadcast/DeployDAOLogicOptimized.s.sol/11155111/run-1713864124.json @@ -0,0 +1,245 @@ +{ + "transactions": [ + { + "hash": "0x992ca4f70c62a5af2707e4187f7873a56f96ad58827c7e695370cd0bbb18411c", + "transactionType": "CREATE", + "contractName": "NounsDAOAdmin", + "contractAddress": "0x02e813dbeaddefe9921f4a2093206aefef4453d6", + "function": null, + "arguments": null, + "transaction": { + "from": "0xad36c32f3c28a9214adcf50a09998de1d3b0ee06", + "to": null, + "gas": "0x277cd7", + "value": null, + "input": "0x61230c61003a600b82828239805160001a60731461002d57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600436106102315760003560e01c8063a267a3d11161013a578063db725e17116100c2578063e9c714f211610086578063e9c714f21461052f578063ec91deda14610544578063ee186559146104a2578063f5f4714c14610564578063fd22b60a146104dc57600080fd5b8063db725e17146104d3578063dfcda1ef146104dc578063e2560772146104e6578063e5eb5abf14610506578063e7951bb91461052657600080fd5b8063c10eb14d11610109578063c10eb14d14610478578063c82fbd0814610371578063cbff4a13146104a2578063ccfa51c9146104ab578063d3f662e1146104b357600080fd5b8063a267a3d114610419578063a78b5f1a14610423578063b71d1a0c14610443578063bf7a29631461046357600080fd5b80632df01bdb116101bd57806374b157b81161018c57806374b157b8146103795780637a3da69114610399578063842e4dae146103b95780639547aecb146103d957806397d048e5146103f957600080fd5b80632df01bdb1461031157806344697f981461033157806350196db31461035157806351e313e01461037157600080fd5b80631e7b5d3a116102045780631e7b5d3a146102ad57806326e6dcb0146102c957806327126e67146102d25780632b5ca189146102dc5780632cfc81c6146102fc57600080fd5b806306ef9d36146102365780630dc0ce3f146102585780630ea2d98c1461026d5780631dfb1b5a1461028d575b600080fd5b81801561024257600080fd5b50610256610251366004611ef2565b610584565b005b81801561026457600080fd5b506102566105f2565b81801561027957600080fd5b50610256610288366004611ef2565b610624565b81801561029957600080fd5b506102566102a8366004611ef2565b610715565b6102b66103e881565b6040519081526020015b60405180910390f35b6102b661177081565b6102b66212750081565b8180156102e857600080fd5b506102566102f7366004611f24565b6107f6565b81801561030857600080fd5b50610256610891565b81801561031d57600080fd5b5061025661032c366004611f5d565b610986565b81801561033d57600080fd5b5061025661034c366004611f78565b610a2c565b81801561035d57600080fd5b5061025661036c366004611fcd565b610ad3565b6102b6600181565b81801561038557600080fd5b50610256610394366004611f24565b610c67565b8180156103a557600080fd5b506102566103b4366004611fcd565b610d28565b8180156103c557600080fd5b506102566103d4366004611ef2565b610ecc565b8180156103e557600080fd5b506102566103f4366004612034565b610f82565b81801561040557600080fd5b50610256610414366004611ef2565b610fb8565b6102b66202a30081565b81801561042f57600080fd5b5061025661043e3660046120a7565b6110a6565b81801561044f57600080fd5b5061025661045e366004611f5d565b611129565b81801561046f57600080fd5b506102566111a7565b81801561048457600080fd5b5061048d611262565b604080519283529015156020830152016102c0565b6102b661c4e081565b6102b660c881565b8180156104bf57600080fd5b506102566104ce366004611f5d565b611320565b6102b6611c2081565b6102b6620189c081565b8180156104f257600080fd5b50610256610501366004611f24565b6113b7565b81801561051257600080fd5b50610256610521366004611f24565b611436565b6102b66107d081565b81801561053b57600080fd5b506102566114ef565b81801561055057600080fd5b5061025661055f3660046120e9565b611605565b81801561057057600080fd5b5061025661057f366004611f5d565b6117de565b6000546001600160a01b031633146105af57604051633057182d60e21b815260040160405180910390fd5b7f8008239436e26bac1476fd338f5a2ec6415794efc1afa04145a4845547f37adc60006017015460408051918252602082018490520160405180910390a1601755565b6000546001600160a01b0316331461061d57604051633057182d60e21b815260040160405180910390fd5b6000601955565b6000546001600160a01b0316331461064f57604051633057182d60e21b815260040160405180910390fd5b611c2081101580156106645750620189c08111155b6106cf5760405162461bcd60e51b815260206004820152603160248201527f4e6f756e7344414f3a3a5f736574566f74696e67506572696f643a20696e76616044820152701b1a59081d9bdd1a5b99c81c195c9a5bd9607a1b60648201526084015b60405180910390fd5b600580549082905560408051828152602081018490527f7e3f7f0708a84de9203036abaa450dccc85ad5ff52f78c170f3edb55cf5e882891015b60405180910390a15050565b6000546001600160a01b0316331461074057604051633057182d60e21b815260040160405180910390fd5b600181101580156107545750620189c08111155b6107b85760405162461bcd60e51b815260206004820152602f60248201527f4e6f756e7344414f3a3a5f736574566f74696e6744656c61793a20696e76616c60448201526e696420766f74696e672064656c617960881b60648201526084016106c6565b600480549082905560408051828152602081018490527fc565b045403dc03c2eea82b81a0465edad9e2e7fc4d97e11421c209da93d7a939101610709565b6000546001600160a01b0316331461082157604051633057182d60e21b815260040160405180910390fd5b600061082f43825b9061185c565b60408101805163ffffffff851690915290915061084b82611b73565b6040805163ffffffff8084168252851660208201527f5e3adb1066359dafa23c629f245d93543856115700821dcb4debc416f393c46991015b60405180910390a1505050565b6000600e01546001600160a01b031633146108bf57604051631bd9bb1b60e31b815260040160405180910390fd5b600354600e546040517fc5644f3588a066b15dcf6b636b74aadca57cfaccf608d9de7d8786364b7a8d0292610902926001600160a01b0391821692911690612123565b60405180910390a1600e546001600160a01b031660005b60030180546001600160a01b0319166001600160a01b03928316179055600e546040517f7ad92e57a52c4e3e83ba624622b14e3a5efa0160dd6f9a7975c43ea66bad79ea9261096c921690600090612123565b60405180910390a1600e80546001600160a01b0319169055565b6000546001600160a01b031633146109b157604051633057182d60e21b815260040160405180910390fd5b7ff890a07a97cb2de686a62235272191a50a2113c4fda17ce6ab5ffd20a06d56d36000601001546040516109f791600160601b90046001600160a01b0316908490612123565b60405180910390a1601080546001600160a01b03909216600160601b026bffffffffffffffffffffffff909216919091179055565b6000546001600160a01b03163314610a5757604051633057182d60e21b815260040160405180910390fd5b600980546001600160a01b038086166001600160a01b0319928316811790935560188054868316908416811790915560008054928616929093168217909255604080519384526020840192909252908201527f13c01549e11ee7e3b2c89b08a2fd55875d85aaf1aa217bf18d1ab0f88f959d2490606001610884565b6000546001600160a01b03163314610afe57604051633057182d60e21b815260040160405180910390fd5b6000610b0a4382610829565b90506117708261ffff161115610b885760405162461bcd60e51b815260206004820152603d60248201527f4e6f756e7344414f3a3a5f7365744d617851756f72756d566f7465734250533a60448201527f20696e76616c6964206d61782071756f72756d20766f7465732062707300000060648201526084016106c6565b805161ffff80841691161115610c155760405162461bcd60e51b815260206004820152604660248201527f4e6f756e7344414f3a3a5f7365744d617851756f72756d566f7465734250533a60448201527f206d696e2071756f72756d20766f7465732062707320677265617465722074686064820152650c2dc40dac2f60d31b608482015260a4016106c6565b60208101805161ffff8416909152610c2c82611b73565b6040805161ffff8084168252851660208201527f4bfb1235074b38f02e5cf8ba90f535905417c196a12654f65ee0584512d706429101610884565b6000546001600160a01b03163314610c9257604051633057182d60e21b815260040160405180910390fd5b61c4e08163ffffffff161115610cbb576040516388a79ca760e01b815260040160405180910390fd5b6010805463ffffffff838116680100000000000000008181026bffffffff0000000000000000198516179094556040805194909304919091168084526020840191909152917fd185da00ceb738d5e65ef6936975bcb81fe742adc63d901592003d7bc22f4dfa9101610709565b6000546001600160a01b03163314610d5357604051633057182d60e21b815260040160405180910390fd5b6000610d5f4382610829565b905060c88261ffff1610158015610d7c57506107d08261ffff1611155b610dee5760405162461bcd60e51b815260206004820152603d60248201527f4e6f756e7344414f3a3a5f7365744d696e51756f72756d566f7465734250533a60448201527f20696e76616c6964206d696e2071756f72756d20766f7465732062707300000060648201526084016106c6565b806020015161ffff168261ffff161115610e7f5760405162461bcd60e51b815260206004820152604660248201527f4e6f756e7344414f3a3a5f7365744d696e51756f72756d566f7465734250533a60448201527f206d696e2071756f72756d20766f7465732062707320677265617465722074686064820152650c2dc40dac2f60d31b608482015260a4016106c6565b805161ffff83168252610e9182611b73565b6040805161ffff8084168252851660208201527ffaeebe30d875e399189096ea49fea81bd41fe6dfc86ad3550639063219e607789101610884565b6000546001600160a01b03163314610ef757604051633057182d60e21b815260040160405180910390fd5b62127500811115610f1b57604051637762590b60e01b815260040160405180910390fd5b6202a300811015610f3f57604051633430477560e11b815260040160405180910390fd5b7ffa0345f15af4cde74f214a8800528bd12cb260c12d8669007af35d869cb6877360006016015460408051918252602082018490520160405180910390a1601655565b610f8b86610986565b610f94856117de565b610f9e84846110a6565b610fa782610ecc565b610fb081610584565b505050505050565b6000546001600160a01b03163314610fe357604051633057182d60e21b815260040160405180910390fd5b60018110158015610ff657506103e88111155b6110685760405162461bcd60e51b815260206004820152603f60248201527f4e6f756e7344414f3a3a5f73657450726f706f73616c5468726573686f6c643a60448201527f20696e76616c69642070726f706f73616c207468726573686f6c64206270730060648201526084016106c6565b600680549082905560408051828152602081018490527ffc216faa269bf440fb06aa490693f409461bde9cdcb949c7b9f2cb79589e7a589101610709565b6000546001600160a01b031633146110d157604051633057182d60e21b815260040160405180910390fd5b6110db8282611d61565b6040517f6158953ac4c84a0a8642793ade32098d1ecd12702db9ce2eb7c72c4463a8fb0790611110906012908590859061213d565b60405180910390a161112460128383611e83565b505050565b6000546001600160a01b0316331461115457604051633057182d60e21b815260040160405180910390fd5b600180546001600160a01b038381166001600160a01b03198316179092556040519116907fca4f2f25d0898edd99413412fb94012f9e54ec8142f9b093e7720646a95b16a9906107099083908590612123565b6000600301546001600160a01b031633146112125760405162461bcd60e51b815260206004820152602560248201527f4e6f756e7344414f3a3a5f6275726e5665746f506f7765723a207665746f6572604482015264206f6e6c7960d81b60648201526084016106c6565b7fc5644f3588a066b15dcf6b636b74aadca57cfaccf608d9de7d8786364b7a8d02600060030154604051611252916001600160a01b031690600090612123565b60405180910390a1600080610919565b60008080546001600160a01b0316331461128f57604051633057182d60e21b815260040160405180910390fd5b6040514790600090339083908381818185875af1925050503d80600081146112d3576040519150601f19603f3d011682016040523d82523d6000602084013e6112d8565b606091505b50506040805184815282151560208201529192507f2aeb20ed0ead73e7bc740154a0b979547bc9e00691d84a700e6454ada9fe4679910160405180910390a190925090509091565b6000600301546001600160a01b0316331461134e57604051631387214760e01b815260040160405180910390fd5b7f7ad92e57a52c4e3e83ba624622b14e3a5efa0160dd6f9a7975c43ea66bad79ea6000600e015460405161138d916001600160a01b0316908490612123565b60405180910390a1600e80546001600160a01b0319166001600160a01b0392909216919091179055565b6000546001600160a01b031633146113e257604051633057182d60e21b815260040160405180910390fd5b6010805463ffffffff83811663ffffffff1983168117909355604080519190921680825260208201939093527f581878c50ce0b9e3ff58adfe29b7a807191bef3c1623340a0ad1d0d8433ebf869101610709565b6000546001600160a01b0316331461146157604051633057182d60e21b815260040160405180910390fd5b61c4e08163ffffffff16111561148a5760405163024c1d4b60e31b815260040160405180910390fd5b6010805463ffffffff83811664010000000081810267ffffffff00000000198516179094556040805194909304919091168084526020840191909152917ff860ba522a6e820ac6577b201d9314604a19ad2e264913d8361821e3659568db9101610709565b6000600101546001600160a01b03163314801561150b57503315155b61156a5760405162461bcd60e51b815260206004820152602a60248201527f4e6f756e7344414f3a3a5f61636365707441646d696e3a2070656e64696e672060448201526961646d696e206f6e6c7960b01b60648201526084016106c6565b60008054600180546001600160a01b03198084166001600160a01b03838116918217909655911690915560405192909116917ff9ffabca9c8276e99321725bcb43fb076a6c66a54b7f21c4e8146d8519b417dc906115cb9084908490612123565b60405180910390a17fca4f2f25d0898edd99413412fb94012f9e54ec8142f9b093e7720646a95b16a9816000604051610709929190612123565b6000546001600160a01b0316331461163057604051633057182d60e21b815260040160405180910390fd5b60c88361ffff16108061164857506107d08361ffff16115b156116665760405163db8a74af60e01b815260040160405180910390fd5b6117708261ffff16111561168d5760405163143abf4360e21b815260040160405180910390fd5b8161ffff168361ffff1611156116b6576040516362c564d560e11b815260040160405180910390fd5b60006116c24382610829565b9050600060405180606001604052808661ffff1681526020018561ffff1681526020018463ffffffff1681525090506116fa81611b73565b815181516040805161ffff93841681529290911660208301527ffaeebe30d875e399189096ea49fea81bd41fe6dfc86ad3550639063219e60778910160405180910390a17f4bfb1235074b38f02e5cf8ba90f535905417c196a12654f65ee0584512d706428260200151826020015160405161178792919061ffff92831681529116602082015260400190565b60405180910390a160408083015182820151825163ffffffff9283168152911660208201527f5e3adb1066359dafa23c629f245d93543856115700821dcb4debc416f393c469910160405180910390a15050505050565b6000546001600160a01b0316331461180957604051633057182d60e21b815260040160405180910390fd5b601180546001600160a01b038381166001600160a01b03198316179092556040519116907f5f317d96631add203c522c8ecc74fd6144c936367e2205ac922331fb12b670b4906107099083908590612123565b6040805160608101825260008082526020820181905291810191909152600061189d8360405180606001604052806040815260200161229760409139611e2a565b600d85015490915060008190036118f45760405180606001604052806118c68760070154611e5a565b61ffff1681526020016118dc8760070154611e5a565b61ffff16815260006020909101529250611b6d915050565b63ffffffff8216600d860161190a6001846121e9565b8154811061191a5761191a6121fc565b600091825260209091206002909102015463ffffffff16116119ad57600d85016119456001836121e9565b81548110611955576119556121fc565b6000918252602091829020604080516060810182526002939093029091016001015461ffff8082168452620100008204169383019390935264010000000090920463ffffffff16918101919091529250611b6d915050565b8163ffffffff1685600d016000815481106119ca576119ca6121fc565b600091825260209091206002909102015463ffffffff1611156119ff5760405180606001604052806118c68760070154611e5a565b600080611a0d6001846121e9565b90505b81811115611b035760006002611a2684846121e9565b611a309190612212565b611a3a90836121e9565b9050600088600d018281548110611a5357611a536121fc565b60009182526020918290206040805180820182526002909302909101805463ffffffff9081168452825160608101845260019092015461ffff808216845262010000820416838701526401000000009004811692820192909252928201929092528051909250878216911603611ad457602001519550611b6d945050505050565b805163ffffffff80881691161015611aee57819350611afc565b611af96001836121e9565b92505b5050611a10565b86600d018281548110611b1857611b186121fc565b6000918252602091829020604080516060810182526002939093029091016001015461ffff8082168452620100008204169383019390935264010000000090920463ffffffff16918101919091529450505050505b92915050565b6000611bb4436040518060400160405280601c81526020017f626c6f636b206e756d6265722065786365656473203332206269747300000000815250611e2a565b600d549091508015801590611c01575063ffffffff8216600d611bd86001846121e9565b81548110611be857611be86121fc565b600091825260209091206002909102015463ffffffff16145b15611c8e5782600d611c146001846121e9565b81548110611c2457611c246121fc565b60009182526020918290208351600160029093029091019190910180549284015160409094015163ffffffff166401000000000267ffffffff000000001961ffff958616620100000263ffffffff1990951695909316949094179290921716919091179055505050565b5060408051808201825263ffffffff92831681526020808201948552600d805460018101825560009190915291517fd7b6990105719101dabeb77144f2a3385c8033acd3af97e9423a695e81ad1eb56002909302928301805491861663ffffffff19928316179055945180517fd7b6990105719101dabeb77144f2a3385c8033acd3af97e9423a695e81ad1eb690930180549282015191909401519094166401000000000267ffffffff000000001961ffff95861662010000029290961694909216939093179290921792909216179055565b6000819003611d6e575050565b60005b611d7c6001836121e9565b811015611124576000611d90826001612234565b90505b82811015611e2157838382818110611dad57611dad6121fc565b9050602002016020810190611dc29190611f5d565b6001600160a01b0316848484818110611ddd57611ddd6121fc565b9050602002016020810190611df29190611f5d565b6001600160a01b031603611e1957604051630254983f60e41b815260040160405180910390fd5b600101611d93565b50600101611d71565b60008163ffffffff841115611e525760405162461bcd60e51b81526004016106c69190612247565b509192915050565b600061ffff821115611e7f5760405163555abf0160e11b815260040160405180910390fd5b5090565b828054828255906000526020600020908101928215611ed6579160200282015b82811115611ed65781546001600160a01b0319166001600160a01b03843516178255602090920191600190910190611ea3565b50611e7f9291505b80821115611e7f5760008155600101611ede565b600060208284031215611f0457600080fd5b5035919050565b803563ffffffff81168114611f1f57600080fd5b919050565b600060208284031215611f3657600080fd5b611f3f82611f0b565b9392505050565b80356001600160a01b0381168114611f1f57600080fd5b600060208284031215611f6f57600080fd5b611f3f82611f46565b600080600060608486031215611f8d57600080fd5b611f9684611f46565b9250611fa460208501611f46565b9150611fb260408501611f46565b90509250925092565b803561ffff81168114611f1f57600080fd5b600060208284031215611fdf57600080fd5b611f3f82611fbb565b60008083601f840112611ffa57600080fd5b50813567ffffffffffffffff81111561201257600080fd5b6020830191508360208260051b850101111561202d57600080fd5b9250929050565b60008060008060008060a0878903121561204d57600080fd5b61205687611f46565b955061206460208801611f46565b9450604087013567ffffffffffffffff81111561208057600080fd5b61208c89828a01611fe8565b979a9699509760608101359660809091013595509350505050565b600080602083850312156120ba57600080fd5b823567ffffffffffffffff8111156120d157600080fd5b6120dd85828601611fe8565b90969095509350505050565b6000806000606084860312156120fe57600080fd5b61210784611fbb565b925061211560208501611fbb565b9150611fb260408501611f0b565b6001600160a01b0392831681529116602082015260400190565b6000604082016040835280865480835260608501915087600052602092508260002060005b828110156121875781546001600160a01b031684529284019260019182019101612162565b505050838103828501528481528590820160005b868110156121c7576001600160a01b036121b484611f46565b168252918301919083019060010161219b565b50979650505050505050565b634e487b7160e01b600052601160045260246000fd5b81810381811115611b6d57611b6d6121d3565b634e487b7160e01b600052603260045260246000fd5b60008261222f57634e487b7160e01b600052601260045260246000fd5b500490565b80820180821115611b6d57611b6d6121d3565b60006020808352835180602085015260005b8181101561227557858101830151858201604001528201612259565b506000604082860101526040601f19601f830116850101925050509291505056fe4e6f756e7344414f3a3a67657444796e616d696351756f72756d506172616d7341743a20626c6f636b206e756d62657220657863656564732033322062697473a2646970667358221220c5e5aef6847a19b009419ec27b21f32c87b71c941e50267d3a1a5da2521c32ae64736f6c63430008170033", + "nonce": "0x140", + "chainId": "0xaa36a7", + "accessList": null, + "type": null + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x6365742b0e5dba31c0c11d73a1998fc4c5fe197a57f2c1e27cec0bea4f285184", + "transactionType": "CREATE", + "contractName": "NounsDAODynamicQuorum", + "contractAddress": "0x970583ad744c3f73eafc7f25591373ba17bdd286", + "function": null, + "arguments": null, + "transaction": { + "from": "0xad36c32f3c28a9214adcf50a09998de1d3b0ee06", + "to": null, + "gas": "0x3c5f4", + "value": null, + "input": "0x61027a61003a600b82828239805160001a60731461002d57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600436106100355760003560e01c8063bb2960751461003a575b600080fd5b61004d610048366004610131565b61005f565b60405190815260200160405180910390f35b6000808361006f866127106101f8565b610079919061020f565b90506000620f424082856040015163ffffffff1661009791906101f8565b6100a1919061020f565b9050600081856000015161ffff166100b99190610231565b905060006100cf866020015161ffff16836100e7565b90506100db8188610101565b98975050505050505050565b60008183106100f657816100f8565b825b90505b92915050565b600061271061011084846101f8565b6100f8919061020f565b803561ffff8116811461012c57600080fd5b919050565b600080600083850360a081121561014757600080fd5b84359350602085013592506060603f198201121561016457600080fd5b506040516060810181811067ffffffffffffffff8211171561019657634e487b7160e01b600052604160045260246000fd5b80604052506101a76040860161011a565b81526101b56060860161011a565b6020820152608085013563ffffffff811681146101d157600080fd5b604082015292959194509192509050565b634e487b7160e01b600052601160045260246000fd5b80820281158282048414176100fb576100fb6101e2565b60008261022c57634e487b7160e01b600052601260045260246000fd5b500490565b808201808211156100fb576100fb6101e256fea26469706673582212208d1cbada5250b0f0ee7f487f17b8024885b2c4a3e362b79a95a6ab87356ad76864736f6c63430008170033", + "nonce": "0x141", + "chainId": "0xaa36a7", + "accessList": null, + "type": null + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0xc0328521eb096b2b664efd70f89a555d94c03a0ec48c29bcdd4b16b31a4d1135", + "transactionType": "CREATE", + "contractName": "NounsDAOFork", + "contractAddress": "0x3f08ce1a659c34737d1a1aae437bf5a99a1857be", + "function": null, + "arguments": null, + "transaction": { + "from": "0xad36c32f3c28a9214adcf50a09998de1d3b0ee06", + "to": null, + "gas": "0x15fc5d", + "value": null, + "input": "0x61131761003a600b82828239805160001a60731461002d57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600436106100925760003560e01c8063704a3b1211610065578063704a3b12146101125780637a868d3e14610152578063aeaa6be614610172578063f667e1141461019257600080fd5b80630577a8461461009757806313d419f6146100b957806319244b17146100df5780636055f935146100f2575b600080fd5b8180156100a357600080fd5b506100b76100b2366004610efe565b6101b2565b005b6100cc6100c7366004610f4a565b6102f8565b6040519081526020015b60405180910390f35b6100cc6100ed366004610f4a565b610379565b8180156100fe57600080fd5b506100b761010d366004610efe565b6103a0565b81801561011e57600080fd5b5061013261012d366004610f4a565b6103c2565b604080516001600160a01b039384168152929091166020830152016100d6565b81801561015e57600080fd5b506100b761016d366004610f63565b61063c565b81801561017e57600080fd5b506100b761018d36600461104c565b6107e1565b81801561019e57600080fd5b506100b76101ad366004610f63565b610866565b60158301544210156101d7576040516366c8a93b60e01b815260040160405180910390fd5b6010830154604051633567f93d60e11b8152600160601b9091046001600160a01b0316908190636acff27a90610215903390879087906004016110dd565b600060405180830381600087803b15801561022f57600080fd5b505af1158015610243573d6000803e3d6000fd5b50505050336001600160a01b0316816001600160a01b031663d7e53db06040518163ffffffff1660e01b8152600401602060405180830381865afa15801561028f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102b3919061110b565b63ffffffff167f7e066a27b070725cdb5ae51be8128dc95d65af0841137f77ec895c775f69849985856040516102ea929190611138565b60405180910390a350505050565b600081601001600c9054906101000a90046001600160a01b03166001600160a01b031663aa34213b6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561034f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103739190611154565b92915050565b6000612710826017015461038c84610aa1565b6103969190611183565b610373919061119a565b60098301546103bd908490849084906001600160a01b0316610c1d565b505050565b6000806103d28360150154421090565b156103f0576040516366c8a93b60e01b815260040160405180910390fd5b600083601001600c9054906101000a90046001600160a01b031690506000816001600160a01b031663aa34213b6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561044c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104709190611154565b905061047b85610379565b811161049a57604051630698c25760e11b815260040160405180910390fd5b60008560160154426104ac91906111bc565b601187015460405163fb14694360e01b8152600481018390526001600160a01b03868116602483015292935091169063fb1469439060440160408051808303816000875af1158015610502573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061052691906111cf565b909550935061053f86868461053a83610aa1565b610ce7565b6000836001600160a01b031663c163de3d6040518163ffffffff1660e01b81526004016020604051808303816000875af1158015610581573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105a5919061110b565b6013880180546001600160a01b038981166001600160a01b0319928316811790935560148b018054918a1691909216811790915560158a0185905560408051928352602083019190915281018490526060810185905290915063ffffffff8216907fb924f7ec9fa839e53ec987276a1a33b95a0aa0796ca86204f365925ac2dbded99060800160405180910390a250505050915091565b6015870154421015610661576040516366c8a93b60e01b815260040160405180910390fd5b6010870154600160601b90046001600160a01b031660005b8681101561072357600a8901546001600160a01b03166342842e0e33848b8b868181106106a8576106a8611209565b6040516001600160e01b031960e088901b1681526001600160a01b03958616600482015294909316602485015250602090910201356044820152606401600060405180830381600087803b1580156106ff57600080fd5b505af1158015610713573d6000803e3d6000fd5b5050600190920191506106799050565b50336001600160a01b0316816001600160a01b031663d7e53db06040518163ffffffff1660e01b8152600401602060405180830381865afa15801561076c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610790919061110b565b63ffffffff167f9a9bbe8a8a2c2b1e1d690cccd211b60ef1d2976f404800ed20604e57d3ed0f2d8989898989896040516107cf9695949392919061121f565b60405180910390a35050505050505050565b60098401546001600160a01b03908116908216036108125760405163c37a1e1760e01b815260040160405180910390fd5b61081e84848484610c1d565b604080518381526001600160a01b03831660208201527f855244575056ebffdfb115e332dfa96f1cd148bfe5bf486758fdd2d55b6fe9eb91015b60405180910390a150505050565b6015870154421061088a57604051635a7d97a760e11b815260040160405180910390fd5b6010870154600988015460138901546001600160a01b03600160601b909304831692918216916108c1918b91168961053a83610aa1565b60005b8781101561096e57600a8a01546001600160a01b03166323b872dd33848c8c868181106108f3576108f3611209565b6040516001600160e01b031960e088901b1681526001600160a01b03958616600482015294909316602485015250602090910201356044820152606401600060405180830381600087803b15801561094a57600080fd5b505af115801561095e573d6000803e3d6000fd5b5050600190920191506108c49050565b5060148901546040516374ea764760e01b81526001600160a01b03909116906374ea7647906109a59033908c908c906004016110dd565b600060405180830381600087803b1580156109bf57600080fd5b505af11580156109d3573d6000803e3d6000fd5b50505050336001600160a01b03166001836001600160a01b031663d7e53db06040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a21573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a45919061110b565b610a4f919061127e565b63ffffffff167f96ca5dab079aba8ed43c71a25c6090b5bce0e3f9ebcb4080816655b7a2d5a36f8a8a8a8a8a8a604051610a8e9695949392919061121f565b60405180910390a3505050505050505050565b600081601001600c9054906101000a90046001600160a01b03166001600160a01b0316639b3c1e226040518163ffffffff1660e01b8152600401602060405180830381865afa158015610af8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b1c9190611154565b600a83015460098401546040516370a0823160e01b81526001600160a01b0391821660048201529116906370a0823190602401602060405180830381865afa158015610b6c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b909190611154565b83600a0160009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610be5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c099190611154565b610c1391906112a2565b61037391906112a2565b83546001600160a01b03163314610c4757604051633057182d60e21b815260040160405180910390fd5b601084015460405163341f601360e21b8152600160601b9091046001600160a01b03169063d07d804c90610c83908690869086906004016112b5565b600060405180830381600087803b158015610c9d57600080fd5b505af1158015610cb1573d6000803e3d6000fd5b505050507e5508ab2be53c6629a9db1afe9702076dc2c4c4f344d60e711a315891d7141e838383604051610858939291906112b5565b60098401546001600160a01b0316600082610d03858431611183565b610d0d919061119a565b6040516364a197f360e01b81526001600160a01b03878116600483015260248201839052919250908316906364a197f390604401600060405180830381600087803b158015610d5b57600080fd5b505af1158015610d6f573d6000803e3d6000fd5b50505050601286015460005b81811015610ea8576000886012018281548110610d9a57610d9a611209565b60009182526020822001546040516370a0823160e01b81526001600160a01b03888116600483015290911692508790899084906370a0823190602401602060405180830381865afa158015610df3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e179190611154565b610e219190611183565b610e2b919061119a565b90508015610e9e576040516323e5d69960e21b81526001600160a01b038a81166004830152838116602483015260448201839052871690638f975a6490606401600060405180830381600087803b158015610e8557600080fd5b505af1158015610e99573d6000803e3d6000fd5b505050505b5050600101610d7b565b5050505050505050565b60008083601f840112610ec457600080fd5b50813567ffffffffffffffff811115610edc57600080fd5b6020830191508360208260051b8501011115610ef757600080fd5b9250929050565b600080600060408486031215610f1357600080fd5b83359250602084013567ffffffffffffffff811115610f3157600080fd5b610f3d86828701610eb2565b9497909650939450505050565b600060208284031215610f5c57600080fd5b5035919050565b60008060008060008060006080888a031215610f7e57600080fd5b87359650602088013567ffffffffffffffff80821115610f9d57600080fd5b610fa98b838c01610eb2565b909850965060408a0135915080821115610fc257600080fd5b610fce8b838c01610eb2565b909650945060608a0135915080821115610fe757600080fd5b818a0191508a601f830112610ffb57600080fd5b81358181111561100a57600080fd5b8b602082850101111561101c57600080fd5b60208301945080935050505092959891949750929550565b6001600160a01b038116811461104957600080fd5b50565b6000806000806060858703121561106257600080fd5b84359350602085013567ffffffffffffffff81111561108057600080fd5b61108c87828801610eb2565b90945092505060408501356110a081611034565b939692955090935050565b81835260006001600160fb1b038311156110c457600080fd5b8260051b80836020870137939093016020019392505050565b6001600160a01b038416815260406020820181905260009061110290830184866110ab565b95945050505050565b60006020828403121561111d57600080fd5b815163ffffffff8116811461113157600080fd5b9392505050565b60208152600061114c6020830184866110ab565b949350505050565b60006020828403121561116657600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b80820281158282048414176103735761037361116d565b6000826111b757634e487b7160e01b600052601260045260246000fd5b500490565b808201808211156103735761037361116d565b600080604083850312156111e257600080fd5b82516111ed81611034565b60208401519092506111fe81611034565b809150509250929050565b634e487b7160e01b600052603260045260246000fd5b60608152600061123360608301888a6110ab565b82810360208401526112468187896110ab565b90508281036040840152838152838560208301376000602085830101526020601f19601f860116820101915050979650505050505050565b63ffffffff82811682821603908082111561129b5761129b61116d565b5092915050565b818103818111156103735761037361116d565b6040815260006112c96040830185876110ab565b905060018060a01b038316602083015294935050505056fea2646970667358221220fd802a6052690f91ee05466d04b1d277dd3a3f33cdfc92bf23e0ec0373c36d9a64736f6c63430008170033", + "nonce": "0x142", + "chainId": "0xaa36a7", + "accessList": null, + "type": null + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0xacd69dc1124b78c0e1941053a221a43cd0c3751eada70aee92fa8cac7e79963b", + "transactionType": "CREATE", + "contractName": "NounsDAOProposals", + "contractAddress": "0x81ede38efc867818bf77978514f5dca76c20a050", + "function": null, + "arguments": null, + "transaction": { + "from": "0xad36c32f3c28a9214adcf50a09998de1d3b0ee06", + "to": null, + "gas": "0x4ffaae", + "value": null, + "input": "0x6147f961003a600b82828239805160001a60731461002d57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600436106101155760003560e01c806383478b43116100ac578063b0a3fc381161007b578063b0a3fc38146102ac578063b2faf4d4146102cc578063b7aa3e57146102ec578063ddb639831461030c578063f9df1e191461032c57600080fd5b806383478b431461021e578063853b94a01461023e57806392be51d814610265578063ac982f381461028557600080fd5b80633ce52dbe116100e85780633ce52dbe1461019e5780635e6ab1ac146101be57806373d0ed2f146101de5780637b55bff3146101fe57600080fd5b806320606b701461011a57806320660f531461015457806336e7048a14610174578063370d35771461017c575b600080fd5b6101417f8cad95687ba82c2ce50e74f7b754645e5117c3a5bec8151c0726d5857980a86681565b6040519081526020015b60405180910390f35b81801561016057600080fd5b5061014161016f3660046138a0565b61034c565b610141600a81565b81801561018857600080fd5b5061019c61019736600461394f565b6104bc565b005b8180156101aa57600080fd5b5061019c6101b936600461394f565b6104ea565b8180156101ca57600080fd5b5061019c6101d936600461394f565b6109b1565b6101f16101ec36600461394f565b610cd5565b60405161014b9190613987565b81801561020a57600080fd5b5061019c6102193660046139af565b610cea565b81801561022a57600080fd5b5061019c610239366004613ab8565b610d4e565b6101417fd4eafb6bc770edecb5da52765bc3f50af948bfe1b8344cf115f8ee7fefe55ec781565b61027861027336600461394f565b610daf565b60405161014b9190613b9c565b6101417fe5a9e6d2702042f3612beac0f605312204baddec2d19d1338da7e37e6c67d6ee81565b8180156102b857600080fd5b5061019c6102c7366004613ca3565b610f2c565b8180156102d857600080fd5b5061019c6102e736600461394f565b610f87565b8180156102f857600080fd5b5061019c610307366004613d25565b61118f565b61031f61031a36600461394f565b611211565b60405161014b9190613db5565b81801561033857600080fd5b5061019c610347366004613ee4565b61144f565b6000845160000361037057604051637a4783fb60e01b815260040160405180910390fd5b61037984611738565b6103a36040518060600160405280600063ffffffff16815260200160008152602001600081525090565b60088701546103b3906001613fb8565b600888018190556103c3906117cf565b63ffffffff1681526103d487611838565b602082018190526103e69088906119b4565b6040820181905281516020830151600092610407928b929091908a896119c4565b90506000806104238a8a8a8a886000015163ffffffff16611b8d565b91509150805160000361044957604051637a4783fb60e01b815260040160405180910390fd5b8360400151821161046d5760405163ead8241560e01b815260040160405180910390fd5b805161048290601285019060208401906132b4565b506104a7838261049f87602001518e611e5290919063ffffffff16565b8b8b8b611e6c565b5050905163ffffffff16979650505050505050565b6000818152600b830160205260408120906104d78483611f46565b90506104e4848383611f7e565b50505050565b60006104f683836121b2565b9050600281600a81111561050c5761050c613971565b14806105295750600381600a81111561052757610527613971565b145b806105455750600681600a81111561054357610543613971565b145b806105615750600781600a81111561055f5761055f613971565b145b8061057d5750600881600a81111561057b5761057b613971565b145b1561059b57604051635598baf360e01b815260040160405180910390fd5b6000828152600b840160205260408120600180820154600a87015492936001600160a01b039182169390911691829063782d6fe19085906105dc9043613fcb565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401602060405180830381865afa158015610625573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106499190613fde565b6001600160601b031690506000336001600160a01b0316846001600160a01b03161490506000856012018054806020026020016040519081016040528092919081815260200182805480156106c757602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116106a9575b5050505050905060005b81518110156107d257828061071057508181815181106106f3576106f361400e565b60200260200101516001600160a01b0316336001600160a01b0316145b9250846001600160a01b031663782d6fe18383815181106107335761073361400e565b60200260200101516001436107489190613fcb565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401602060405180830381865afa158015610791573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107b59190613fde565b6107c8906001600160601b031685613fb8565b93506001016106d1565b5081806107e3575085600201548311155b6108475760405162461bcd60e51b815260206004820152602a60248201527f4e6f756e7344414f3a3a63616e63656c3a2070726f706f7365722061626f7665604482015269081d1a1c995cda1bdb1960b21b60648201526084015b60405180910390fd5b600e8601805460ff1916600117905560006108628a88611f46565b905060005b600588015481101561097157816001600160a01b031663591fcdfe8960050183815481106108975761089761400e565b60009182526020909120015460068b0180546001600160a01b0390921691859081106108c5576108c561400e565b90600052602060002001548b60070185815481106108e5576108e561400e565b906000526020600020018c60080186815481106109045761090461400e565b906000526020600020018d600401546040518663ffffffff1660e01b81526004016109339594939291906140db565b600060405180830381600087803b15801561094d57600080fd5b505af1158015610961573d6000803e3d6000fd5b5050600190920191506108679050565b506040518981527f789cf55be980739dad1d0699b93b58e806b51c9d96619bfa8fe0a28abaa7b30c9060200160405180910390a150505050505050505050565b60046109bd83836121b2565b600a8111156109ce576109ce613971565b14610a415760405162461bcd60e51b815260206004820152603f60248201527f4e6f756e7344414f3a3a71756575653a2070726f706f73616c2063616e206f6e60448201527f6c79206265207175657565642069662069742069732073756363656564656400606482015260840161083e565b6000818152600b83016020526040812090610a5c8483611f46565b90506000816001600160a01b0316636a42b8f86040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a9e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ac29190614127565b610acc9042613fb8565b905060005b6005840154811015610c8d57610c8583856005018381548110610af657610af661400e565b6000918252602090912001546006870180546001600160a01b039092169185908110610b2457610b2461400e565b9060005260206000200154876007018581548110610b4457610b4461400e565b906000526020600020018054610b5990614024565b80601f0160208091040260200160405190810160405280929190818152602001828054610b8590614024565b8015610bd25780601f10610ba757610100808354040283529160200191610bd2565b820191906000526020600020905b815481529060010190602001808311610bb557829003601f168201915b5050505050886008018681548110610bec57610bec61400e565b906000526020600020018054610c0190614024565b80601f0160208091040260200160405190810160405280929190818152602001828054610c2d90614024565b8015610c7a5780601f10610c4f57610100808354040283529160200191610c7a565b820191906000526020600020905b815481529060010190602001808311610c5d57829003601f168201915b5050505050876123ab565b600101610ad1565b506004830181905560408051858152602081018390527f9a2e42fd6722813d69113e7d0079d3d940171428df7373df9c7f7617cfda2892910160405180910390a15050505050565b6000610ce183836121b2565b90505b92915050565b610cf8888888888888612554565b336001600160a01b0316877fd92cc1350c3c114b08bfa9ca07e42b8d07adf3c440ac299943edfbfb9be890ac888888888888604051610d3c9695949392919061421b565b60405180910390a35050505050505050565b610d5c878787878787612554565b336001600160a01b0316867f2588d794bdaac5e181a3efca6937bf6bac4e2f42f43dcfcf0492b3d8b54be0658787878787604051610d9e95949392919061429d565b60405180910390a350505050505050565b610e37604051806101e001604052806000815260200160006001600160a01b03168152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160001515815260200160001515815260200160001515815260200160008152602001600081525090565b6000828152600b8401602090815260409182902082516101e081018452815463ffffffff90811680835260018401546001600160a01b031694830194909452600283015494820194909452909290916060830191610e979188916125f916565b81526004830154602082015260098301546040820152600a8301546060820152600b8301546080820152600c83015460a0820152600d83015460c0820152600e83015460ff808216151560e0840152610100808304821615159084015262010000909104161515610120820152601083015461014082015260119092015463ffffffff16610160909201919091529392505050565b6000858152600b870160205260409020610f47878783612652565b336001600160a01b0316867fb326c35bcac6caacafa6cd1190bb9dc1a4e0aad7a7985e193818797dfbec990587878787604051610d9e9493929190614327565b60038201546001600160a01b0316610fb257604051631efc808d60e31b815260040160405180910390fd5b60038201546001600160a01b03163314610fdf57604051631387214760e01b815260040160405180910390fd5b6007610feb83836121b2565b600a811115610ffc57610ffc613971565b0361101a57604051636c0a12d560e01b815260040160405180910390fd5b6000818152600b830160205260408120600e8101805461ff001916610100179055906110468483611f46565b905060005b600583015481101561115557816001600160a01b031663591fcdfe84600501838154811061107b5761107b61400e565b6000918252602090912001546006860180546001600160a01b0390921691859081106110a9576110a961400e565b90600052602060002001548660070185815481106110c9576110c961400e565b906000526020600020018760080186815481106110e8576110e861400e565b9060005260206000200188600401546040518663ffffffff1660e01b81526004016111179594939291906140db565b600060405180830381600087803b15801561113157600080fd5b505af1158015611145573d6000803e3d6000fd5b50506001909201915061104b9050565b506040518381527fde0cea2a3a0097cc3d981d40c375407760e85bc9c5e69aea449ac3885f8615c69060200160405180910390a150505050565b600082826040516111a192919061434e565b60408051918290038220336000818152600f89016020908152848220848352905292909220805460ff191660011790559250907f45f194850d9c26cfb50dad5456a1c64997b6a4d461d0159f372282ba183d854d90611203908690869061435e565b60405180910390a250505050565b6112b76040518061026001604052806000815260200160006001600160a01b03168152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160001515815260200160001515815260200160001515815260200160008152602001600081526020016060815260200160008152602001600081526020016000151581525090565b6000828152600b84016020908152604091829020825161026081018452815463ffffffff90811680835260018401546001600160a01b0316948301949094526002830154948201949094529092909160608301916113179188916125f916565b815260048301546020808301919091526009840154604080840191909152600a8501546060840152600b8501546080840152600c85015460a0840152600d85015460c0840152600e85015460ff808216151560e08601526101008083048216151590860152620100009091041615156101208401526010850154610140840152601185015463ffffffff1661016084015260128501805482518185028101850190935280835261018090940193919290919083018282801561140257602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116113e4575b505050918352505060118301546001600160401b03600160401b820481166020840152600160801b90910416604082015260139092015460ff161515606090920191909152905092915050565b61145883611738565b835160000361147a57604051637a4783fb60e01b815260040160405180910390fd5b6000858152600b870160205260409020600a61149688886121b2565b600a8111156114a7576114a7613971565b146114c5576040516339abb30760e21b815260040160405180910390fd5b60018101546001600160a01b031633146114f257604051631d6b368d60e01b815260040160405180910390fd5b60008160120180548060200260200160405190810160405280929190818152602001828054801561154c57602002820191906000526020600020905b81546001600160a01b0316815260019091019060200180831161152e575b5050505050905080518651146115755760405163b92ba76160e01b815260040160405180910390fd5b6000876115833388886126e2565b604051602001611594929190614372565b604051602081830303815290604052905060005b8751811015611666576115f68a838a84815181106115c8576115c861400e565b60200260200101517fe5a9e6d2702042f3612beac0f605312204baddec2d19d1338da7e37e6c67d6ee61292d565b8781815181106116085761160861400e565b6020026020010151602001516001600160a01b031683828151811061162f5761162f61400e565b60200260200101516001600160a01b03161461165e57604051631d6b368d60e01b815260040160405180910390fd5b6001016115a8565b508551805161167f9160058601916020909101906132b4565b5060208087015180516116989260068701920190613315565b50604086015180516116b4916007860191602090910190613350565b50606086015180516116d09160088601916020909101906133a2565b50336001600160a01b0316887fd92cc1350c3c114b08bfa9ca07e42b8d07adf3c440ac299943edfbfb9be890ac886000015189602001518a604001518b606001518b8b6040516117259695949392919061421b565b60405180910390a3505050505050505050565b602081015151815151141580611755575060408101515181515114155b80611767575060608101515181515114155b156117855760405163ccb0ce3f60e01b815260040160405180910390fd5b8051516000036117a857604051630f24cd7360e01b815260040160405180910390fd5b805151600a10156117cc576040516308e3b1eb60e11b815260040160405180910390fd5b50565b600063ffffffff8211156118345760405162461bcd60e51b815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203360448201526532206269747360d01b606482015260840161083e565b5090565b600081601001600c9054906101000a90046001600160a01b03166001600160a01b0316639b3c1e226040518163ffffffff1660e01b8152600401602060405180830381865afa15801561188f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118b39190614127565b600a83015460098401546040516370a0823160e01b81526001600160a01b0391821660048201529116906370a0823190602401602060405180830381865afa158015611903573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119279190614127565b83600a0160009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561197c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119a09190614127565b6119aa9190613fcb565b610ce49190613fcb565b6000610ce18360060154836129f1565b601086015460009081906119ee906119e990600160401b900463ffffffff1643613fb8565b612a0a565b905060008860040154826001600160401b0316611a0b9190613fb8565b90506000896005015482611a1f9190613fb8565b63ffffffff808b166000818152600b8e01602090815260409091208054938a166401000000000267ffffffffffffffff199094169092179290921781556001810180546001600160a01b03191633179055600281018b905588518051919750929350611a9192600588019201906132b4565b506020808701518051611aaa9260068801920190613315565b5060408601518051611ac6916007870191602090910190613350565b5060608601518051611ae29160088701916020909101906133a2565b5060098401829055600a840181905560108401879055611b01436117cf565b60118501805463ffffffff191663ffffffff92909216919091179055611b26426117cf565b6011850180546001600160401b03909516600160401b026fffffffffffffffff00000000000000001963ffffffff9390931664010000000002929092166fffffffffffffffffffffffff000000001990951694909417179092555090979650505050505050565b600a8501546000906060906001600160a01b031682611bad3388886126e2565b905087516001600160401b03811115611bc857611bc861347d565b604051908082528060200260200182016040528015611bf1578160200160208202803683370190505b5092506000805b8951811015611d7b57611c468b848c8481518110611c1857611c1861400e565b60200260200101517fd4eafb6bc770edecb5da52765bc3f50af948bfe1b8344cf115f8ee7fefe55ec761292d565b60008a8281518110611c5a57611c5a61400e565b6020026020010151602001519050611c728c82612a72565b60006001600160a01b03861663782d6fe183611c8f600143613fcb565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401602060405180830381865afa158015611cd8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cfc9190613fde565b6001600160601b0316905080600003611d16575050611d73565b818785611d2281614398565b965081518110611d3457611d3461400e565b6001600160a01b039283166020918202929092018101919091529083166000908152600c8f0190915260409020899055611d6e8189613fb8565b975050505b600101611bf8565b508851811015611d89578084525b611d938a33612a72565b336000818152600c8c01602052604090208790556001600160a01b0384169063782d6fe190611dc3600143613fcb565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401602060405180830381865afa158015611e0c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e309190613fde565b611e43906001600160601b031686613fb8565b94505050509550959350505050565b6000610ce1611e618443612b28565b5161ffff16836129f1565b855483516020850151604080870151606088015160098c0154600a8d015493517f7d84a6263ae0d98d3329bd7b46bb4e8d6f98cd35a7adb45c274c8b7fd5ebd5e097611ecf9763ffffffff90911696339691959094909390929091908c906143b1565b60405180910390a185546011870154600288015460405163ffffffff808616947fd9d12651716feaac10e3b79bd2960ad42ebfd84969b71a2e226ec99972a8712e94611f369491909216928b926001600160401b03600160401b9091041691908b9061444f565b60405180910390a2505050505050565b601381015460009060ff1615611f6a575060188201546001600160a01b0316610ce4565b5060098201546001600160a01b0316610ce4565b60058254611f9390859063ffffffff166121b2565b600a811115611fa457611fa4613971565b14612019576040805162461bcd60e51b81526020600482015260248101919091527f4e6f756e7344414f3a3a657865637574653a2070726f706f73616c2063616e2060448201527f6f6e6c7920626520657865637574656420696620697420697320717565756564606482015260840161083e565b601583015442101561203e57604051633183594360e21b815260040160405180910390fd5b600e8201805462ff000019166201000017905560005b600583015481101561217057816001600160a01b0316630825f38f8460050183815481106120845761208461400e565b6000918252602090912001546006860180546001600160a01b0390921691859081106120b2576120b261400e565b90600052602060002001548660070185815481106120d2576120d261400e565b906000526020600020018760080186815481106120f1576120f161400e565b9060005260206000200188600401546040518663ffffffff1660e01b81526004016121209594939291906140db565b6000604051808303816000875af115801561213f573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526121679190810190614494565b50600101612054565b50815460405163ffffffff90911681527f712ae1383f79ac853f8d882153778e0260ef8f03b504e2866e0593e04d2b291f9060200160405180910390a1505050565b600081836008015410156122145760405162461bcd60e51b8152602060048201526024808201527f4e6f756e7344414f3a3a73746174653a20696e76616c69642070726f706f73616044820152631b081a5960e21b606482015260840161083e565b6000828152600b840160205260409020600e810154610100900460ff1615612240576008915050610ce4565b600e81015460ff1615612257576002915050610ce4565b6011810154600160401b90046001600160401b0316431161227c57600a915050610ce4565b80600901544311612291576000915050610ce4565b80600a015443116122a6576001915050610ce4565b6011810154600160801b90046001600160401b031643116122cb576009915050610ce4565b6122d58482612e3d565b156122e4576003915050610ce4565b80600401546000036122fa576004915050610ce4565b600e81015462010000900460ff1615612317576007915050610ce4565b6123218482611f46565b6001600160a01b031663c1a287e26040518163ffffffff1660e01b8152600401602060405180830381865afa15801561235e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123829190614127565b81600401546123919190613fb8565b42106123a1576006915050610ce4565b6005915050610ce4565b856001600160a01b031663f2b0653786868686866040516020016123d395949392919061450a565b604051602081830303815290604052805190602001206040518263ffffffff1660e01b815260040161240791815260200190565b602060405180830381865afa158015612424573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124489190614543565b156124d45760405162461bcd60e51b815260206004820152605060248201527f4e6f756e7344414f3a3a71756575654f72526576657274496e7465726e616c3a60448201527f206964656e746963616c2070726f706f73616c20616374696f6e20616c72656160648201526f6479207175657565642061742065746160801b608482015260a40161083e565b604051633a66f90160e01b81526001600160a01b03871690633a66f90190612508908890889088908890889060040161450a565b6020604051808303816000875af1158015612527573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061254b9190614127565b50505050505050565b61257d604051806080016040528086815260200185815260200184815260200183815250611738565b6000858152600b870160205260409020612598878783612652565b84516125ad90600583019060208801906132b4565b5083516125c39060068301906020870190613315565b5082516125d99060078301906020860190613350565b5081516125ef90600883019060208501906133a2565b5050505050505050565b6000818152600b8301602052604081206010810154820361261f57600301549050610ce4565b600c8101546010820154601183015461264a92919061264590889063ffffffff16612b28565b612e73565b949350505050565b600a61265e84846121b2565b600a81111561266f5761266f613971565b1461268d576040516339abb30760e21b815260040160405180910390fd5b60018101546001600160a01b031633146126ba57604051631d6b368d60e01b815260040160405180910390fd5b6012810154156126dd57604051630e13f93360e11b815260040160405180910390fd5b505050565b606060008360400151516001600160401b038111156127035761270361347d565b60405190808252806020026020018201604052801561272c578160200160208202803683370190505b50905060005b84604001515181101561278957846040015181815181106127555761275561400e565b6020026020010151805190602001208282815181106127765761277661400e565b6020908102919091010152600101612732565b5060008460600151516001600160401b038111156127a9576127a961347d565b6040519080825280602002602001820160405280156127d2578160200160208202803683370190505b50905060005b85606001515181101561282f57856060015181815181106127fb576127fb61400e565b60200260200101518051906020012082828151811061281c5761281c61400e565b60209081029190910101526001016127d8565b508451604051879161284391602001614565565b60405160208183030381529060405280519060200120866020015160405160200161286e91906145a4565b604051602081830303815290604052805190602001208460405160200161289591906145a4565b60405160208183030381529060405280519060200120846040516020016128bc91906145a4565b60408051601f1981840301815282825280516020918201208b518c8301206001600160a01b0390981691840191909152908201949094526060810192909252608082015260a081019190915260c081019190915260e001604051602081830303815290604052925050509392505050565b81518051602091820120818401516001600160a01b03166000908152600f870183526040808220838352909352919091205460ff161561298057604051634260f73960e01b815260040160405180910390fd5b60006129928386866040015130612efb565b90506129a78460200151828660000151612ff3565b6129c457604051638baa579f60e01b815260040160405180910390fd5b83604001514211156129e957604051630819bdcd60e01b815260040160405180910390fd5b505050505050565b6000612710612a0084846145ce565b610ce191906145e5565b60006001600160401b038211156118345760405162461bcd60e51b815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203660448201526534206269747360d01b606482015260840161083e565b6001600160a01b0381166000908152600c8301602052604090205480156126dd576000612a9f84836121b2565b9050600981600a811115612ab557612ab5613971565b1480612ad25750600181600a811115612ad057612ad0613971565b145b80612aee5750600081600a811115612aec57612aec613971565b145b80612b0a5750600a81600a811115612b0857612b08613971565b145b156104e4576040516306bee79560e01b815260040160405180910390fd5b60408051606081018252600080825260208201819052918101919091526000612b698360405180606001604052806040815260200161478460409139613054565b600d8501549091506000819003612bc0576040518060600160405280612b928760070154613084565b61ffff168152602001612ba88760070154613084565b61ffff16815260006020909101529250610ce4915050565b63ffffffff8216600d8601612bd6600184613fcb565b81548110612be657612be661400e565b600091825260209091206002909102015463ffffffff1611612c7957600d8501612c11600183613fcb565b81548110612c2157612c2161400e565b6000918252602091829020604080516060810182526002939093029091016001015461ffff8082168452620100008204169383019390935264010000000090920463ffffffff16918101919091529250610ce4915050565b8163ffffffff1685600d01600081548110612c9657612c9661400e565b600091825260209091206002909102015463ffffffff161115612ccb576040518060600160405280612b928760070154613084565b600080612cd9600184613fcb565b90505b81811115612dcf5760006002612cf28484613fcb565b612cfc91906145e5565b612d069083613fcb565b9050600088600d018281548110612d1f57612d1f61400e565b60009182526020918290206040805180820182526002909302909101805463ffffffff9081168452825160608101845260019092015461ffff808216845262010000820416838701526401000000009004811692820192909252928201929092528051909250878216911603612da057602001519550610ce4945050505050565b805163ffffffff80881691161015612dba57819350612dc8565b612dc5600183613fcb565b92505b5050612cdc565b86600d018281548110612de457612de461400e565b6000918252602091829020604080516060810182526002939093029091016001015461ffff8082168452620100008204169383019390935264010000000090920463ffffffff1691810191909152979650505050505050565b600b810154600c820154600091908111158061264a57508254612e6b90859063ffffffff908116906125f916565b119392505050565b60008083612e83866127106145ce565b612e8d91906145e5565b90506000620f424082856040015163ffffffff16612eab91906145ce565b612eb591906145e5565b9050600081856000015161ffff16612ecd9190613fb8565b90506000612ee3866020015161ffff16836130a9565b9050612eef81886129f1565b98975050505050505050565b600080858585604051602001612f1393929190614607565b60408051601f198184030181528282528051602091820120838301835260098452684e6f756e732044414f60b81b9382019390935281517f8cad95687ba82c2ce50e74f7b754645e5117c3a5bec8151c0726d5857980a866818301527fe1dd93b3612547b4bb7c3d429f3df8508d84f5a4f63b5e2e44340b94698e6b3b818401524660608201526001600160a01b0387166080808301919091528351808303909101815260a0820193849052805192019190912061190160f01b835260a2820181905260c29091018390526042909120919250905b979650505050505050565b600080600061300285856130bf565b9092509050600081600481111561301b5761301b613971565b1480156130395750856001600160a01b0316826001600160a01b0316145b8061304a575061304a868686613104565b9695505050505050565b60008163ffffffff84111561307c5760405162461bcd60e51b815260040161083e9190614634565b509192915050565b600061ffff8211156118345760405163555abf0160e11b815260040160405180910390fd5b60008183106130b85781610ce1565b5090919050565b60008082516041036130f55760208301516040840151606085015160001a6130e9878285856131f0565b945094505050506130fd565b506000905060025b9250929050565b6000806000856001600160a01b0316631626ba7e60e01b868660405160240161312e929190614647565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b031990941693909317909252905161316c9190614660565b600060405180830381855afa9150503d80600081146131a7576040519150601f19603f3d011682016040523d82523d6000602084013e6131ac565b606091505b50915091508180156131c057506020815110155b801561304a57508051630b135d3f60e11b906131e59083016020908101908401614127565b149695505050505050565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a083111561322757506000905060036132ab565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa15801561327b573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b0381166132a4576000600192509250506132ab565b9150600090505b94509492505050565b828054828255906000526020600020908101928215613309579160200282015b8281111561330957825182546001600160a01b0319166001600160a01b039091161782556020909201916001909101906132d4565b506118349291506133f4565b828054828255906000526020600020908101928215613309579160200282015b82811115613309578251825591602001919060010190613335565b828054828255906000526020600020908101928215613396579160200282015b82811115613396578251829061338690826146c4565b5091602001919060010190613370565b50611834929150613409565b8280548282559060005260206000209081019282156133e8579160200282015b828111156133e857825182906133d890826146c4565b50916020019190600101906133c2565b50611834929150613426565b5b8082111561183457600081556001016133f5565b8082111561183457600061341d8282613443565b50600101613409565b8082111561183457600061343a8282613443565b50600101613426565b50805461344f90614024565b6000825580601f1061345f575050565b601f0160209004906000526020600020908101906117cc91906133f4565b634e487b7160e01b600052604160045260246000fd5b604051606081016001600160401b03811182821017156134b5576134b561347d565b60405290565b604051608081016001600160401b03811182821017156134b5576134b561347d565b604051601f8201601f191681016001600160401b03811182821017156135055761350561347d565b604052919050565b60006001600160401b038211156135265761352661347d565b5060051b60200190565b60006001600160401b038211156135495761354961347d565b50601f01601f191660200190565b600082601f83011261356857600080fd5b813561357b61357682613530565b6134dd565b81815284602083860101111561359057600080fd5b816020850160208301376000918101602001919091529392505050565b80356001600160a01b03811681146135c457600080fd5b919050565b600082601f8301126135da57600080fd5b813560206135ea6135768361350d565b82815260059290921b8401810191818101908684111561360957600080fd5b8286015b848110156136995780356001600160401b038082111561362d5760008081fd5b908801906060828b03601f19018113156136475760008081fd5b61364f613493565b87840135838111156136615760008081fd5b61366f8d8a83880101613557565b825250604092506136818385016135ad565b8189015292013590820152835291830191830161360d565b509695505050505050565b600082601f8301126136b557600080fd5b813560206136c56135768361350d565b8083825260208201915060208460051b8701019350868411156136e757600080fd5b602086015b84811015613699576136fd816135ad565b83529183019183016136ec565b600082601f83011261371b57600080fd5b8135602061372b6135768361350d565b8083825260208201915060208460051b87010193508684111561374d57600080fd5b602086015b848110156136995780358352918301918301613752565b600082601f83011261377a57600080fd5b8135602061378a6135768361350d565b82815260059290921b840181019181810190868411156137a957600080fd5b8286015b848110156136995780356001600160401b038111156137cc5760008081fd5b6137da8986838b0101613557565b8452509183019183016137ad565b6000608082840312156137fa57600080fd5b6138026134bb565b905081356001600160401b038082111561381b57600080fd5b613827858386016136a4565b8352602084013591508082111561383d57600080fd5b6138498583860161370a565b6020840152604084013591508082111561386257600080fd5b61386e85838601613769565b6040840152606084013591508082111561388757600080fd5b5061389484828501613769565b60608301525092915050565b600080600080600060a086880312156138b857600080fd5b8535945060208601356001600160401b03808211156138d657600080fd5b6138e289838a016135c9565b955060408801359150808211156138f857600080fd5b61390489838a016137e8565b9450606088013591508082111561391a57600080fd5b5061392788828901613557565b925050608086013563ffffffff8116811461394157600080fd5b809150509295509295909350565b6000806040838503121561396257600080fd5b50508035926020909101359150565b634e487b7160e01b600052602160045260246000fd5b60208101600b83106139a957634e487b7160e01b600052602160045260246000fd5b91905290565b600080600080600080600080610100898b0312156139cc57600080fd5b883597506020890135965060408901356001600160401b03808211156139f157600080fd5b6139fd8c838d016136a4565b975060608b0135915080821115613a1357600080fd5b613a1f8c838d0161370a565b965060808b0135915080821115613a3557600080fd5b613a418c838d01613769565b955060a08b0135915080821115613a5757600080fd5b613a638c838d01613769565b945060c08b0135915080821115613a7957600080fd5b613a858c838d01613557565b935060e08b0135915080821115613a9b57600080fd5b50613aa88b828c01613557565b9150509295985092959890939650565b600080600080600080600060e0888a031215613ad357600080fd5b873596506020880135955060408801356001600160401b0380821115613af857600080fd5b613b048b838c016136a4565b965060608a0135915080821115613b1a57600080fd5b613b268b838c0161370a565b955060808a0135915080821115613b3c57600080fd5b613b488b838c01613769565b945060a08a0135915080821115613b5e57600080fd5b613b6a8b838c01613769565b935060c08a0135915080821115613b8057600080fd5b50613b8d8a828b01613557565b91505092959891949750929550565b815181526020808301516101e0830191613bc0908401826001600160a01b03169052565b5060408301516040830152606083015160608301526080830151608083015260a083015160a083015260c083015160c083015260e083015160e083015261010080840151818401525061012080840151818401525061014080840151613c298285018215159052565b505061016083810151151590830152610180808401511515908301526101a080840151908301526101c092830151929091019190915290565b60008083601f840112613c7457600080fd5b5081356001600160401b03811115613c8b57600080fd5b6020830191508360208285010111156130fd57600080fd5b60008060008060008060808789031215613cbc57600080fd5b863595506020870135945060408701356001600160401b0380821115613ce157600080fd5b613ced8a838b01613c62565b90965094506060890135915080821115613d0657600080fd5b50613d1389828a01613c62565b979a9699509497509295939492505050565b600080600060408486031215613d3a57600080fd5b8335925060208401356001600160401b03811115613d5757600080fd5b613d6386828701613c62565b9497909650939450505050565b60008151808452602080850194506020840160005b83811015613daa5781516001600160a01b031687529582019590820190600101613d85565b509495945050505050565b602081528151602082015260006020830151613ddc60408401826001600160a01b03169052565b506040830151606083015260608301516080830152608083015160a083015260a083015160c083015260c083015160e083015260e0830151610100818185015280850151915050610120818185015280850151915050610140818185015280850151915050610160613e518185018315159052565b8401519050610180613e668482018315159052565b84015190506101a0613e7b8482018315159052565b8401516101c0848101919091528401516101e08085019190915284015161026061020080860182905291925090613eb6610280860184613d70565b9086015161022086810191909152860151610240808701919091529095015115159301929092525090919050565b60008060008060008060c08789031215613efd57600080fd5b863595506020870135945060408701356001600160401b0380821115613f2257600080fd5b613f2e8a838b016135c9565b95506060890135915080821115613f4457600080fd5b613f508a838b016137e8565b94506080890135915080821115613f6657600080fd5b613f728a838b01613557565b935060a0890135915080821115613f8857600080fd5b50613f9589828a01613557565b9150509295509295509295565b634e487b7160e01b600052601160045260246000fd5b80820180821115610ce457610ce4613fa2565b81810381811115610ce457610ce4613fa2565b600060208284031215613ff057600080fd5b81516001600160601b038116811461400757600080fd5b9392505050565b634e487b7160e01b600052603260045260246000fd5b600181811c9082168061403857607f821691505b60208210810361405857634e487b7160e01b600052602260045260246000fd5b50919050565b6000815461406b81614024565b80855260206001838116801561408857600181146140a2576140d0565b60ff1985168884015283151560051b8801830195506140d0565b866000528260002060005b858110156140c85781548a82018601529083019084016140ad565b890184019650505b505050505092915050565b60018060a01b038616815284602082015260a06040820152600061410260a083018661405e565b8281036060840152614114818661405e565b9150508260808301529695505050505050565b60006020828403121561413957600080fd5b5051919050565b60008151808452602080850194506020840160005b83811015613daa57815187529582019590820190600101614155565b60005b8381101561418c578181015183820152602001614174565b50506000910152565b600081518084526141ad816020860160208601614171565b601f01601f19169290920160200192915050565b60008282518085526020808601955060208260051b8401016020860160005b8481101561420e57601f198684030189526141fc838351614195565b988401989250908301906001016141e0565b5090979650505050505050565b60c08152600061422e60c0830189613d70565b82810360208401526142408189614140565b9050828103604084015261425481886141c1565b9050828103606084015261426881876141c1565b9050828103608084015261427c8186614195565b905082810360a08401526142908185614195565b9998505050505050505050565b60a0815260006142b060a0830188613d70565b82810360208401526142c28188614140565b905082810360408401526142d681876141c1565b905082810360608401526142ea81866141c1565b90508281036080840152612eef8185614195565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b60408152600061433b6040830186886142fe565b8281036020840152612fe88185876142fe565b8183823760009101908152919050565b60208152600061264a6020830184866142fe565b8281526000825161438a816020850160208701614171565b919091016020019392505050565b6000600182016143aa576143aa613fa2565b5060010190565b63ffffffff8a1681526001600160a01b0389166020820152610120604082018190526000906143e28382018b613d70565b905082810360608401526143f6818a614140565b9050828103608084015261440a81896141c1565b905082810360a084015261441e81886141c1565b90508560c08401528460e084015282810361010084015261443f8185614195565b9c9b505050505050505050505050565b63ffffffff8616815260a06020820152600061446e60a0830187613d70565b6001600160401b0395909516604083015250606081019290925260809091015292915050565b6000602082840312156144a657600080fd5b81516001600160401b038111156144bc57600080fd5b8201601f810184136144cd57600080fd5b80516144db61357682613530565b8181528560208385010111156144f057600080fd5b614501826020830160208601614171565b95945050505050565b60018060a01b038616815284602082015260a06040820152600061453160a0830186614195565b82810360608401526141148186614195565b60006020828403121561455557600080fd5b8151801515811461400757600080fd5b815160009082906020808601845b838110156145985781516001600160a01b031685529382019390820190600101614573565b50929695505050505050565b815160009082906020808601845b83811015614598578151855293820193908201906001016145b2565b8082028115828204841417610ce457610ce4613fa2565b60008261460257634e487b7160e01b600052601260045260246000fd5b500490565b8381526000835161461f816020850160208801614171565b60209201918201929092526040019392505050565b602081526000610ce16020830184614195565b82815260406020820152600061264a6040830184614195565b60008251614672818460208701614171565b9190910192915050565b601f8211156126dd576000816000526020600020601f850160051c810160208610156146a55750805b601f850160051c820191505b818110156129e9578281556001016146b1565b81516001600160401b038111156146dd576146dd61347d565b6146f1816146eb8454614024565b8461467c565b602080601f831160018114614726576000841561470e5750858301515b600019600386901b1c1916600185901b1785556129e9565b600085815260208120601f198616915b8281101561475557888601518255948401946001909101908401614736565b50858210156147735787850151600019600388901b60f8161c191681555b5050505050600190811b0190555056fe4e6f756e7344414f3a3a67657444796e616d696351756f72756d506172616d7341743a20626c6f636b206e756d62657220657863656564732033322062697473a26469706673582212203d27194f160b95bf2f25018dac840393c3bd014f71918b4913b59d1cbc642ae964736f6c63430008170033", + "nonce": "0x143", + "chainId": "0xaa36a7", + "accessList": null, + "type": null + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0xd8e5ad5005fa8e231687ee17d418d98e0bf39f486d83f80aec0d71fdff72999a", + "transactionType": "CREATE", + "contractName": "NounsDAOVotes", + "contractAddress": "0x30656985039923eaa1ebb968fe84a1277581f602", + "function": null, + "arguments": null, + "transaction": { + "from": "0xad36c32f3c28a9214adcf50a09998de1d3b0ee06", + "to": null, + "gas": "0x1dc81a", + "value": null, + "input": "0x611a3361003a600b82828239805160001a60731461002d57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600436106100be5760003560e01c8063b73a99c71161007b578063b73a99c714610187578063bc4cd084146101a7578063deaaa7cc146101b3578063e105d84a146101da578063f57e66d1146101fa578063fbfee8761461021a57600080fd5b8063042bc3de146100c357806306fdde03146100e057806320606b70146101155780633be8ef3f1461013c57806350de7cf614610145578063aabb220a14610167575b600080fd5b6100cd62030d4081565b6040519081526020015b60405180910390f35b610108604051806040016040528060098152602001684e6f756e732044414f60b81b81525081565b6040516100d791906115ba565b6100cd7f8cad95687ba82c2ce50e74f7b754645e5117c3a5bec8151c0726d5857980a86681565b6100cd618ca081565b81801561015157600080fd5b50610165610160366004611640565b610225565b005b81801561017357600080fd5b506101656101823660046116b7565b610271565b81801561019357600080fd5b506101656101a23660046116ec565b6102ce565b6100cd642e90edd00081565b6100cd7f150214d74d59b7d1e90c73fc22ef3d991dd0a76b046543d4d80ab92d2a50328f81565b8180156101e657600080fd5b506101656101f5366004611754565b610310565b81801561020657600080fd5b5061016561021536600461179a565b610332565b6100cd637735940081565b61026986868686868080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250889250610593915050565b505050505050565b336000805160206119de8339815191528383610291878584846000610641565b6040805193845260ff90921660208401526001600160601b03169082015260806060820181905260009082015260a00160405180910390a2505050565b336000805160206119de83398151915285856102ee898584846000610641565b86866040516103019594939291906117f2565b60405180910390a25050505050565b61032c8484846040518060200160405280600081525085610593565b50505050565b60408051808201825260098152684e6f756e732044414f60b81b60209182015281517f8cad95687ba82c2ce50e74f7b754645e5117c3a5bec8151c0726d5857980a866818301527fe1dd93b3612547b4bb7c3d429f3df8508d84f5a4f63b5e2e44340b94698e6b3b81840152466060820152306080808301919091528351808303909101815260a0820184528051908301207f150214d74d59b7d1e90c73fc22ef3d991dd0a76b046543d4d80ab92d2a50328f60c083015260e0820189905260ff8816610100808401919091528451808403909101815261012083019094528351939092019290922061190160f01b6101408401526101428301829052610162830181905290916000906101820160408051601f198184030181528282528051602091820120600080855291840180845281905260ff8a169284019290925260608301889052608083018790529092509060019060a0016020604051602081039080840390855afa1580156104ab573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b0381166105265760405162461bcd60e51b815260206004820152602a60248201527f4e6f756e7344414f3a3a63617374566f746542795369673a20696e76616c6964604482015269207369676e617475726560b01b60648201526084015b60405180910390fd5b806001600160a01b03166000805160206119de8339815191528a8a61054f8e868f8f6000610641565b6040805193845260ff90921660208401526001600160601b03169082015260806060820181905260009082015260a00160405180910390a250505050505050505050565b60005a905060006105a78733888887610641565b9050336001600160a01b03166000805160206119de833981519152878784886040516105d69493929190611842565b60405180910390a263ffffffff8316156106205760405163ffffffff841690879033907f651cc9d78606507fdcfc4f37ec37a744d612b1d8f5a73564190577c4f0edb0b690600090a45b6001600160601b038116156106385761063882610804565b50505050505050565b60008061064e87866108f2565b9050600181600a8111156106645761066461187d565b0361067c5761067587868887610afa565b915061071f565b600981600a8111156106905761069061187d565b036106c25760ff8416156106b757604051639aeea66b60e01b815260040160405180910390fd5b610675878688610ea5565b60405162461bcd60e51b815260206004820152602c60248201527f4e6f756e7344414f3a3a63617374566f7465496e7465726e616c3a20766f746960448201526b1b99c81a5cc818db1bdcd95960a21b606482015260840161051d565b6000858152600b88016020908152604080832063ffffffff808816855260149091018352928190208151808301835290548085168252640100000000900484169281019290925280518082019091528151919290918291610782918791166118a9565b63ffffffff1681526020018260200151600161079e91906118c9565b63ffffffff9081169091526000978852600b90990160209081526040808920968b168952601490960181529490962086518154979095015189166401000000000267ffffffffffffffff1990971694909816939093179490941790955550929392505050565b476000819003610812575050565b600061082348642e90edd000611022565b905060006108373a63773594008401611022565b9050600061084e618ca05a87030162030d40611022565b9050600061085e82840286611022565b604051909150600090329083908381818185875af1925050503d80600081146108a3576040519150601f19603f3d011682016040523d82523d6000602084013e6108a8565b606091505b505060408051848152821515602082015291925032917ffabef36fd46c4c3a6ad676521be5367a4dfdbf3faa68d8e826003b1752d68f4f910160405180910390a250505050505050565b600081836008015410156109545760405162461bcd60e51b8152602060048201526024808201527f4e6f756e7344414f3a3a73746174653a20696e76616c69642070726f706f73616044820152631b081a5960e21b606482015260840161051d565b6000828152600b840160205260409020600e810154610100900460ff1615610980576008915050610af4565b600e81015460ff1615610997576002915050610af4565b601181015468010000000000000000900467ffffffffffffffff1643116109c257600a915050610af4565b806009015443116109d7576000915050610af4565b80600a015443116109ec576001915050610af4565b6011810154600160801b900467ffffffffffffffff164311610a12576009915050610af4565b610a1c848261103a565b15610a2b576003915050610af4565b8060040154600003610a41576004915050610af4565b600e81015462010000900460ff1615610a5e576007915050610af4565b610a688482611073565b6001600160a01b031663c1a287e26040518163ffffffff1660e01b8152600401602060405180830381865afa158015610aa5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ac991906118e6565b8160040154610ad891906118ff565b4210610ae8576006915050610af4565b6005915050610af4565b505b92915050565b600060028260ff161115610b765760405162461bcd60e51b815260206004820152603f60248201527f4e6f756e7344414f3a3a63617374566f7465447572696e67566f74696e67506560448201527f72696f64496e7465726e616c3a20696e76616c696420766f7465207479706500606482015260840161051d565b6000848152600b8601602090815260408083206001600160a01b0387168452600f8101909252909120805460ff1615610c215760405162461bcd60e51b815260206004820152604160248201527f4e6f756e7344414f3a3a63617374566f7465447572696e67566f74696e67506560448201527f72696f64496e7465726e616c3a20766f74657220616c726561647920766f74656064820152601960fa1b608482015260a40161051d565b600a870154600983015460405163782d6fe160e01b81526000926001600160a01b03169163782d6fe191610c6d918a916004016001600160a01b03929092168252602082015260400190565b602060405180830381865afa158015610c8a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cae9190611912565b905060008560ff16600103610cdf576010890154600a85015463ffffffff90911690610cdb90439061193b565b1090505b60008115610cf457610cf18a8661103a565b90505b8660ff16600003610d2257826001600160601b031685600c0154610d1891906118ff565b600c860155610d7a565b8660ff16600103610d5057826001600160601b031685600b0154610d4691906118ff565b600b860155610d7a565b8660ff16600203610d7a57826001600160601b031685600d0154610d7491906118ff565b600d8601555b818015610d845750805b8015610da357506011850154600160801b900467ffffffffffffffff16155b8015610db65750610db48a8661103a565b155b15610e595760108a0154600a860154610de791610de29164010000000090910463ffffffff16906118ff565b6110ab565b60118601805467ffffffffffffffff60801b1916600160801b67ffffffffffffffff93841681029190911791829055875460405191909204909216825263ffffffff16907f6553d98dd06f98670b24f69f718cdf9c8ec8e1cc42fb58b9c7908731322273479060200160405180910390a25b505081546001600160601b03821662010000026dffffffffffffffffffffffff00001960ff88166101000261ffff19909316929092176001179190911617909155915050949350505050565b6000828152600b8401602090815260408083206001600160a01b0385168452600f81019092528220805460ff1615610f375760405162461bcd60e51b815260206004820152602f60248201527f4e6f756e7344414f3a3a63617374566f7465496e7465726e616c3a20766f746560448201526e1c88185b1c9958591e481d9bdd1959608a1b606482015260840161051d565b600a860154600983015460405163782d6fe160e01b81526000926001600160a01b03169163782d6fe191610f839189916004016001600160a01b03929092168252602082015260400190565b602060405180830381865afa158015610fa0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fc49190611912565b825461ff001960ff196001600160601b038416620100008102919091166dffffffffffffffffffffffff00ff1990931692909217600117168455600c85015491925061100f916118ff565b600c909301929092555090509392505050565b60008183106110315781611033565b825b9392505050565b600b810154600c820154600091908111158061106b5750825461106890859063ffffffff9081169061111816565b81105b949350505050565b601381015460009060ff1615611097575060188201546001600160a01b0316610af4565b5060098201546001600160a01b0316610af4565b600067ffffffffffffffff8211156111145760405162461bcd60e51b815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203660448201526534206269747360d01b606482015260840161051d565b5090565b6000818152600b8301602052604081206010810154820361113e57600301549050610af4565b600c8101546010820154601183015461106b92919061116490889063ffffffff16611169565b61147e565b604080516060810182526000808252602082018190529181019190915260006111aa8360405180606001604052806040815260200161199e60409139611506565b600d85015490915060008190036112015760405180606001604052806111d38760070154611536565b61ffff1681526020016111e98760070154611536565b61ffff16815260006020909101529250610af4915050565b63ffffffff8216600d860161121760018461193b565b815481106112275761122761194e565b600091825260209091206002909102015463ffffffff16116112ba57600d850161125260018361193b565b815481106112625761126261194e565b6000918252602091829020604080516060810182526002939093029091016001015461ffff8082168452620100008204169383019390935264010000000090920463ffffffff16918101919091529250610af4915050565b8163ffffffff1685600d016000815481106112d7576112d761194e565b600091825260209091206002909102015463ffffffff16111561130c5760405180606001604052806111d38760070154611536565b60008061131a60018461193b565b90505b818111156114105760006002611333848461193b565b61133d9190611964565b611347908361193b565b9050600088600d0182815481106113605761136061194e565b60009182526020918290206040805180820182526002909302909101805463ffffffff9081168452825160608101845260019092015461ffff8082168452620100008204168387015264010000000090048116928201929092529282019290925280519092508782169116036113e157602001519550610af4945050505050565b805163ffffffff808816911610156113fb57819350611409565b61140660018361193b565b92505b505061131d565b86600d0182815481106114255761142561194e565b6000918252602091829020604080516060810182526002939093029091016001015461ffff8082168452620100008204169383019390935264010000000090920463ffffffff1691810191909152979650505050505050565b6000808361148e86612710611986565b6114989190611964565b90506000620f424082856040015163ffffffff166114b69190611986565b6114c09190611964565b9050600081856000015161ffff166114d891906118ff565b905060006114ee866020015161ffff1683611022565b90506114fa818861155b565b98975050505050505050565b60008163ffffffff84111561152e5760405162461bcd60e51b815260040161051d91906115ba565b509192915050565b600061ffff8211156111145760405163555abf0160e11b815260040160405180910390fd5b600061271061156a8484611986565b6110339190611964565b6000815180845260005b8181101561159a5760208185018101518683018201520161157e565b506000602082860101526020601f19601f83011685010191505092915050565b6020815260006110336020830184611574565b803560ff811681146115de57600080fd5b919050565b60008083601f8401126115f557600080fd5b50813567ffffffffffffffff81111561160d57600080fd5b60208301915083602082850101111561162557600080fd5b9250929050565b803563ffffffff811681146115de57600080fd5b60008060008060008060a0878903121561165957600080fd5b8635955060208701359450611670604088016115cd565b9350606087013567ffffffffffffffff81111561168c57600080fd5b61169889828a016115e3565b90945092506116ab90506080880161162c565b90509295509295509295565b6000806000606084860312156116cc57600080fd5b83359250602084013591506116e3604085016115cd565b90509250925092565b60008060008060006080868803121561170457600080fd5b853594506020860135935061171b604087016115cd565b9250606086013567ffffffffffffffff81111561173757600080fd5b611743888289016115e3565b969995985093965092949392505050565b6000806000806080858703121561176a57600080fd5b8435935060208501359250611781604086016115cd565b915061178f6060860161162c565b905092959194509250565b60008060008060008060c087890312156117b357600080fd5b86359550602087013594506117ca604088016115cd565b93506117d8606088016115cd565b92506080870135915060a087013590509295509295509295565b85815260ff851660208201526001600160601b038416604082015260806060820152816080820152818360a0830137600081830160a090810191909152601f909201601f19160101949350505050565b84815260ff841660208201526001600160601b03831660408201526080606082015260006118736080830184611574565b9695505050505050565b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052601160045260246000fd5b6001600160601b03818116838216019080821115610af257610af2611893565b63ffffffff818116838216019080821115610af257610af2611893565b6000602082840312156118f857600080fd5b5051919050565b80820180821115610af457610af4611893565b60006020828403121561192457600080fd5b81516001600160601b038116811461103357600080fd5b81810381811115610af457610af4611893565b634e487b7160e01b600052603260045260246000fd5b60008261198157634e487b7160e01b600052601260045260246000fd5b500490565b8082028115828204841417610af457610af461189356fe4e6f756e7344414f3a3a67657444796e616d696351756f72756d506172616d7341743a20626c6f636b206e756d62657220657863656564732033322062697473b8e138887d0aa13bab447e82de9d5c1777041ecd21ca36ba824ff1e6c07ddda4a264697066735822122043105a1adbc23b09950f1109a24d3d90a2f0b2ecc9d47ae2033b4ca57273b9bb64736f6c63430008170033", + "nonce": "0x144", + "chainId": "0xaa36a7", + "accessList": null, + "type": null + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0xd534b73edd763c42dd5102fb7ec5b3c7b45936edc12dde860bdd8b5c87cb257a", + "transactionType": "CREATE", + "contractName": "NounsDAOLogicV4", + "contractAddress": "0x017b4fd1a03308df03cb9a03a303fe9e6bc8ab7d", + "function": null, + "arguments": null, + "transaction": { + "from": "0xad36c32f3c28a9214adcf50a09998de1d3b0ee06", + "to": null, + "gas": "0x66a8ca", + "value": "0x0", + "input": "0x608060405234801561001057600080fd5b50615cac80620000216000396000f3fe6080604052600436106104405760003560e01c80637d17aa3a11610234578063c37522d41161012e578063da9427c4116100b6578063e48083fe1161007a578063e48083fe14610bd8578063ea3ecd0f14610d64578063f32293d214610d79578063f851a44014610d8e578063fe0d94c114610dac57610447565b8063da9427c414610c87578063da95691a14610ca7578063ddf0b00914610cc7578063e23a9a5214610ce7578063e2742e1814610d3757610447565b8063d27dd112116100fd578063d27dd11214610c01578063d33219b414610c21578063d8bff44014610c3f578063d93150be14610c5d578063da35c66414610c7257610447565b8063c37522d414610b96578063c3dd69eb14610bb8578063c82fbd0814610bd8578063cd0d9eac14610bec57610447565b806397242b8e116101bc578063aa0e23c711610180578063aa0e23c714610b07578063abb308b214610b34578063b112626314610ab1578063b58131b014610b61578063b5cd5bfa14610b7657610447565b806397242b8e14610a715780639a0dfb5314610a91578063a64e024a14610ab1578063a67d063514610ac7578063a9cf82f014610ae557610447565b806383cce0e11161020357806383cce0e1146109e457806384d1d199146109f95780638f1314b614610a1e5780638f1447d914610a3357806390f8c2f414610a5357610447565b80637d17aa3a146109725780637f5ef445146109945780637fa230bd146109af5780638136730f146109c457610447565b80633e2733341161034557806355ce73b1116102cd5780637217024c116102915780637217024c146108cb57806377388b70146108eb5780637757d18d146109205780637b3c71d31461093e5780637bdbe4d01461095e57610447565b806355ce73b1146108295780635678138814610849578063590c1f161461086957806364c0599514610889578063705cb335146108a957610447565b806344fac8f61161031457806344fac8f61461078757806347f4a077146107a757806349e857ea146107d457806353349413146107f45780635408e7f21461080957610447565b80633e273334146107055780633e4f49e61461071a5780633fde324d1461074757806340e58ee51461076757610447565b806328aa53e4116103c857806336a3b5781161039757806336a3b5781461067b57806338b1c2f6146106905780633932abb1146106b05780633b66c516146106c55780633bccf4fd146106e557610447565b806328aa53e4146105d95780632a4fa9fe146105f95780632de45f1814610619578063328dd9821461064b57610447565b806316f1b8cf1161040f57806316f1b8cf1461053757806317977c61146105575780631d28dec71461058d5780631e7b5d3a146105af578063215809ca146105c457610447565b8063013cf08b146104ad57806302a251a3146104e35780630f7b1f081461050257806314a67ea41461052257610447565b3661044757005b60003660606104a17302e813dbeaddefe9921f4a2093206aefef4453d66000368080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610dcc92505050565b80519350602001915050f35b3480156104b957600080fd5b506104cd6104c8366004613b3f565b610dfa565b6040516104da9190613b58565b60405180910390f35b3480156104ef57600080fd5b506005545b6040519081526020016104da565b34801561050e57600080fd5b506104f461051d366004613b3f565b610efe565b34801561052e57600080fd5b506006546104f4565b34801561054357600080fd5b506104f4610552366004613fa1565b610f0a565b34801561056357600080fd5b506104f4610572366004614095565b6001600160a01b03166000908152600c602052604090205490565b34801561059957600080fd5b506105ad6105a8366004613b3f565b610f27565b005b3480156105bb57600080fd5b506103e86104f4565b3480156105d057600080fd5b50611c206104f4565b3480156105e557600080fd5b506105ad6105f43660046140b2565b610f95565b34801561060557600080fd5b506104f4610614366004614174565b611408565b34801561062557600080fd5b50600a546001600160a01b03165b6040516001600160a01b0390911681526020016104da565b34801561065757600080fd5b5061066b610666366004613b3f565b611442565b6040516104da9493929190614374565b34801561068757600080fd5b506104f4611461565b34801561069c57600080fd5b506104f46106ab3660046143c1565b6114de565b3480156106bc57600080fd5b506004546104f4565b3480156106d157600080fd5b506104f46106e0366004614174565b611522565b3480156106f157600080fd5b506105ad6107003660046144a3565b61155c565b34801561071157600080fd5b506104f46115ed565b34801561072657600080fd5b5061073a610735366004613b3f565b611604565b6040516104da9190614507565b34801561075357600080fd5b506105ad610762366004614577565b611682565b34801561077357600080fd5b506105ad610782366004613b3f565b6116f2565b34801561079357600080fd5b506105ad6107a23660046145b8565b611731565b3480156107b357600080fd5b506107c76107c2366004613b3f565b611780565b6040516104da91906145e4565b3480156107e057600080fd5b506105ad6107ef366004614658565b6117a8565b34801561080057600080fd5b506016546104f4565b34801561081557600080fd5b506105ad61082436600461468d565b6117e4565b34801561083557600080fd5b506105ad6108443660046146c4565b611860565b34801561085557600080fd5b506105ad6108643660046145b8565b6118d3565b34801561087557600080fd5b506105ad61088436600461471a565b61191b565b34801561089557600080fd5b506105ad6108a43660046147b3565b61195f565b3480156108b557600080fd5b50601054600160201b900463ffffffff166104f4565b3480156108d757600080fd5b506104f46108e636600461480c565b6119d7565b3480156108f757600080fd5b50610900611a84565b604080516001600160a01b039384168152929091166020830152016104da565b34801561092c57600080fd5b506011546001600160a01b0316610633565b34801561094a57600080fd5b506105ad6109593660046147b3565b611b04565b34801561096a57600080fd5b50600a6104f4565b34801561097e57600080fd5b50601054600160401b900463ffffffff166104f4565b3480156109a057600080fd5b5060105463ffffffff166104f4565b3480156109bb57600080fd5b506104f4611b44565b3480156109d057600080fd5b506105ad6109df366004614912565b611b5b565b3480156109f057600080fd5b506007546104f4565b348015610a0557600080fd5b50601054600160601b90046001600160a01b0316610633565b348015610a2a57600080fd5b506104f4611b9d565b348015610a3f57600080fd5b506105ad610a4e366004614980565b611ba9565b348015610a5f57600080fd5b506018546001600160a01b0316610633565b348015610a7d57600080fd5b506105ad610a8c3660046149bc565b611bfd565b348015610a9d57600080fd5b506104f4610aac366004614af2565b611c97565b348015610abd57600080fd5b50620189c06104f4565b348015610ad357600080fd5b50600e546001600160a01b0316610633565b348015610af157600080fd5b50610afa611d20565b6040516104da9190614baa565b348015610b1357600080fd5b50610b27610b22366004614c06565b611dc5565b6040516104da9190614cd8565b348015610b4057600080fd5b50610b54610b4f366004613b3f565b611dd8565b6040516104da9190614d9f565b348015610b6d57600080fd5b506104f4611e84565b348015610b8257600080fd5b506105ad610b9136600461471a565b611e99565b348015610ba257600080fd5b50610bab611edd565b6040516104da9190614dad565b348015610bc457600080fd5b506105ad610bd3366004614dc0565b611f42565b348015610be457600080fd5b5060016104f4565b348015610bf857600080fd5b506104f4611f84565b348015610c0d57600080fd5b506105ad610c1c366004614658565b611fbf565b348015610c2d57600080fd5b506009546001600160a01b0316610633565b348015610c4b57600080fd5b506003546001600160a01b0316610633565b348015610c6957600080fd5b506015546104f4565b348015610c7e57600080fd5b506008546104f4565b348015610c9357600080fd5b506105ad610ca2366004614e39565b611ffb565b348015610cb357600080fd5b506104f4610cc23660046143c1565b612041565b348015610cd357600080fd5b506105ad610ce2366004613b3f565b612052565b348015610cf357600080fd5b50610d07610d02366004614f38565b612091565b6040805182511515815260208084015160ff1690820152918101516001600160601b0316908201526060016104da565b348015610d4357600080fd5b50610d57610d52366004613b3f565b61211d565b6040516104da9190614f68565b348015610d7057600080fd5b506019546104f4565b348015610d8557600080fd5b506017546104f4565b348015610d9a57600080fd5b506000546001600160a01b0316610633565b348015610db857600080fd5b506105ad610dc7366004613b3f565b612242565b6060610df18383604051806060016040528060278152602001615c1060279139612281565b90505b92915050565b610e82604051806101e001604052806000815260200160006001600160a01b03168152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160001515815260200160001515815260200160001515815260200160008152602001600081525090565b604051631257ca3b60e31b815260006004820152602481018390527381ede38efc867818bf77978514f5dca76c20a050906392be51d8906044016101e060405180830381865af4158015610eda573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610df491906150ad565b6000610df48183612350565b6000610f1c87878787878760006119d7565b979650505050505050565b604051632cbebd3560e21b815260006004820152602481018290527381ede38efc867818bf77978514f5dca76c20a0509063b2faf4d4906044015b60006040518083038186803b158015610f7a57600080fd5b505af4158015610f8e573d6000803e3d6000fd5b5050505050565b6009546001600160a01b031615610fbf57604051630205737f60e61b815260040160405180910390fd5b6000546001600160a01b03163314610fea57604051633057182d60e21b815260040160405180910390fd5b6001600160a01b03871661101157604051637330d04160e11b815260040160405180910390fd5b6001600160a01b0386166110385760405163d2ef0d7160e01b815260040160405180910390fd5b6040516303a8b66360e21b8152823560048201527302e813dbeaddefe9921f4a2093206aefef4453d690630ea2d98c9060240160006040518083038186803b15801561108357600080fd5b505af4158015611097573d6000803e3d6000fd5b5050604051630efd8dad60e11b8152602085013560048201527302e813dbeaddefe9921f4a2093206aefef4453d69250631dfb1b5a915060240160006040518083038186803b1580156110e957600080fd5b505af41580156110fd573d6000803e3d6000fd5b5050604080516397d048e560e01b81529085013560048201527302e813dbeaddefe9921f4a2093206aefef4453d692506397d048e5915060240160006040518083038186803b15801561114f57600080fd5b505af4158015611163573d6000803e3d6000fd5b5050600980546001600160a01b03199081166001600160a01b038c811691909117909255600a805482168b8416179055601080546001600160601b0316600160601b8b85160217905560118054821689841617905560038054909116918716919091179055507302e813dbeaddefe9921f4a2093206aefef4453d6905063ec91deda6111f26020840184615186565b6112026040850160208601615186565b61121260608601604087016151a1565b6040516001600160e01b031960e086901b16815261ffff938416600482015292909116602483015263ffffffff16604482015260640160006040518083038186803b15801561126057600080fd5b505af4158015611274573d6000803e3d6000fd5b505050507302e813dbeaddefe9921f4a2093206aefef4453d663e25607728360600160208101906112a591906151a1565b6040516001600160e01b031960e084901b16815263ffffffff91909116600482015260240160006040518083038186803b1580156112e257600080fd5b505af41580156112f6573d6000803e3d6000fd5b505050507302e813dbeaddefe9921f4a2093206aefef4453d663e5eb5abf83608001602081019061132791906151a1565b6040516001600160e01b031960e084901b16815263ffffffff91909116600482015260240160006040518083038186803b15801561136457600080fd5b505af4158015611378573d6000803e3d6000fd5b505050507302e813dbeaddefe9921f4a2093206aefef4453d66374b157b88360a00160208101906113a991906151a1565b6040516001600160e01b031960e084901b16815263ffffffff9190911660048201526024015b60006040518083038186803b1580156113e757600080fd5b505af41580156113fb573d6000803e3d6000fd5b5050505050505050505050565b6000610f1c604051806080016040528089815260200188815260200187815260200186815250848460006123a9909392919063ffffffff16565b60608080806114526000866124fa565b93509350935093509193509193565b6040516319244b1760e01b815260006004820181905290733f08ce1a659c34737d1a1aae437bf5a99a1857be906319244b17906024015b602060405180830381865af41580156114b5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114d991906151bc565b905090565b60006115186040518060800160405280888152602001878152602001868152602001858152508360008061278f909392919063ffffffff16565b9695505050505050565b6000610f1c6040518060800160405280898152602001888152602001878152602001868152508484600061278f909392919063ffffffff16565b60405163f57e66d160e01b8152600060048201526024810186905260ff8086166044830152841660648201526084810183905260a481018290527330656985039923eaa1ebb968fe84a1277581f6029063f57e66d19060c4015b60006040518083038186803b1580156115ce57600080fd5b505af41580156115e2573d6000803e3d6000fd5b505050505050505050565b60006114d96115fc6000612806565b600090612982565b6040516373d0ed2f60e01b815260006004820181905260248201839052907381ede38efc867818bf77978514f5dca76c20a050906373d0ed2f90604401602060405180830381865af415801561165e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610df491906151d5565b60405163b7aa3e5760e01b81527381ede38efc867818bf77978514f5dca76c20a0509063b7aa3e57906116be906000908690869060040161521f565b60006040518083038186803b1580156116d657600080fd5b505af41580156116ea573d6000803e3d6000fd5b505050505050565b604051631e7296df60e11b815260006004820152602481018290527381ede38efc867818bf77978514f5dca76c20a05090633ce52dbe90604401610f62565b604051637082ec2560e11b81526000600482018190526024820184905260ff8316604483015260648201527330656985039923eaa1ebb968fe84a1277581f6029063e105d84a906084016116be565b6040805160608101825260008082526020820181905291810191909152610df460008361299c565b6040516302bbd42360e11b8152733f08ce1a659c34737d1a1aae437bf5a99a1857be90630577a846906116be9060009086908690600401615274565b6040516383478b4360e01b81527381ede38efc867818bf77978514f5dca76c20a050906383478b4390611828906000908a908a908a908a908a908a9060040161528e565b60006040518083038186803b15801561184057600080fd5b505af4158015611854573d6000803e3d6000fd5b50505050505050505050565b60405163575535f360e11b8152733f08ce1a659c34737d1a1aae437bf5a99a1857be9063aeaa6be69061189e90600090879087908790600401615309565b60006040518083038186803b1580156118b657600080fd5b505af41580156118ca573d6000803e3d6000fd5b50505050505050565b60405163555d910560e11b8152600060048201526024810183905260ff821660448201527330656985039923eaa1ebb968fe84a1277581f6029063aabb220a906064016116be565b604051633d43469f60e11b8152733f08ce1a659c34737d1a1aae437bf5a99a1857be90637a868d3e90611828906000908a908a908a908a908a908a9060040161533c565b60405163286f3e7b60e11b81527330656985039923eaa1ebb968fe84a1277581f602906350de7cf6906119a1906000908890889088908890859060040161537e565b60006040518083038186803b1580156119b957600080fd5b505af41580156119cd573d6000803e3d6000fd5b5050505050505050565b60408051608081018252878152602081018790528082018690526060810185905290516320660f5360e01b81526000917381ede38efc867818bf77978514f5dca76c20a050916320660f5391611a379185918d9189908990600401615516565b602060405180830381865af4158015611a54573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a7891906151bc565b98975050505050505050565b6040516338251d8960e11b8152600060048201819052908190733f08ce1a659c34737d1a1aae437bf5a99a1857be9063704a3b12906024016040805180830381865af4158015611ad8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611afc919061556e565b915091509091565b60405163b73a99c760e01b81527330656985039923eaa1ebb968fe84a1277581f6029063b73a99c7906119a190600090889088908890889060040161559d565b60006114d9611b536000612806565b600090612cae565b60405163286f3e7b60e11b81527330656985039923eaa1ebb968fe84a1277581f602906350de7cf6906115b6906000908990899089908990899060040161537e565b60006114d96000612806565b604051637082ec2560e11b8152600060048201526024810184905260ff8316604482015263ffffffff821660648201527330656985039923eaa1ebb968fe84a1277581f6029063e105d84a9060840161189e565b604080516080810182528781526020810187905280820186905260608101859052905163f9df1e1960e01b81527381ede38efc867818bf77978514f5dca76c20a0509163f9df1e1991611c5d916000918d918d91899089906004016155c6565b60006040518083038186803b158015611c7557600080fd5b505af4158015611c89573d6000803e3d6000fd5b505050505050505050505050565b60405163bb29607560e01b815260009073970583ad744c3f73eafc7f25591373ba17bdd2869063bb29607590611cd59087908790879060040161562c565b602060405180830381865af4158015611cf2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d1691906151bc565b90505b9392505050565b60606000600d01805480602002602001604051908101604052809291908181526020016000905b82821015611dbc57600084815260209081902060408051808201825260028602909201805463ffffffff9081168452825160608101845260019283015461ffff80821683526201000082041682880152600160201b900490911692810192909252828401919091529083529092019101611d47565b50505050905090565b6060611a78600089898989898989612ccb565b611e0b60408051808201825260008082528251606081018452818152602081810183905293810191909152909182015290565b600d805483908110611e1f57611e1f615669565b60009182526020918290206040805180820182526002909302909101805463ffffffff9081168452825160608101845260019092015461ffff80821684526201000082041683870152600160201b900416918101919091529181019190915292915050565b60006114d9611e91611b9d565b6000906130c3565b604051633d99f84560e21b8152733f08ce1a659c34737d1a1aae437bf5a99a1857be9063f667e11490611828906000908a908a908a908a908a908a9060040161533c565b60606000601201805480602002602001604051908101604052809291908181526020018280548015611f3857602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311611f1a575b5050505050905090565b6040516316147f8760e31b81527381ede38efc867818bf77978514f5dca76c20a0509063b0a3fc38906115b6906000908990899089908990899060040161567f565b6040516309ea0cfb60e11b815260006004820181905290733f08ce1a659c34737d1a1aae437bf5a99a1857be906313d419f690602401611498565b604051636055f93560e01b8152733f08ce1a659c34737d1a1aae437bf5a99a1857be90636055f935906116be9060009086908690600401615274565b604051637b55bff360e01b81527381ede38efc867818bf77978514f5dca76c20a05090637b55bff3906113cf906000908b908b908b908b908b908b908b906004016156b2565b600061151886868686866000611408565b60405163179aac6b60e21b815260006004820152602481018290527381ede38efc867818bf77978514f5dca76c20a05090635e6ab1ac90604401610f62565b604080516060808201835260008083526020808401829052838501829052845180840186528281528082018390528501829052868252600b81528482206001600160a01b0387168352600f01815290849020845192830185525460ff80821615158452610100820416918301919091526201000090046001600160601b03169281019290925290610df1565b6121c36040518061026001604052806000815260200160006001600160a01b03168152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160001515815260200160001515815260200160001515815260200160008152602001600081526020016060815260200160008152602001600081526020016000151581525090565b60405163ddb6398360e01b815260006004820152602481018390527381ede38efc867818bf77978514f5dca76c20a0509063ddb6398390604401600060405180830381865af415801561221a573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610df491908101906157ad565b60405163370d357760e01b815260006004820152602481018290527381ede38efc867818bf77978514f5dca76c20a0509063370d357790604401610f62565b6060833b6122e55760405162461bcd60e51b815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f6044820152651b9d1c9858dd60d21b60648201526084015b60405180910390fd5b600080856001600160a01b0316856040516123009190615905565b600060405180830381855af49150503d806000811461233b576040519150601f19603f3d011682016040523d82523d6000602084013e612340565b606091505b50915091506115188282866130d3565b6000818152600b8301602052604081206010810154820361237657600301549050610df4565b600c810154601082015460118301546123a192919061239c90889063ffffffff1661299c565b61310c565b949350505050565b6000806123b586612806565b600a87015490915060009061245c9088906001600160a01b031663782d6fe1336123e0600143615937565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401602060405180830381865afa158015612429573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061244d919061594a565b6001600160601b031684613188565b9050612467866131b6565b612471873361324d565b6008870154612481906001615973565b600888018190556000906124949061330a565b905060006124a6898385878c8b613373565b336000908152600c8b016020908152604080832063ffffffff87169055805192835290820190529091506124e89082906124e08c88612982565b8b8b8b61353a565b5063ffffffff16979650505050505050565b606080606080600086600b0160008781526020019081526020016000209050806005018160060182600701836008018380548060200260200160405190810160405280929190818152602001828054801561257e57602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311612560575b50505050509350828054806020026020016040519081016040528092919081815260200182805480156125d057602002820191906000526020600020905b8154815260200190600101908083116125bc575b5050505050925081805480602002602001604051908101604052809291908181526020016000905b828210156126a457838290600052602060002001805461261790615986565b80601f016020809104026020016040519081016040528092919081815260200182805461264390615986565b80156126905780601f1061266557610100808354040283529160200191612690565b820191906000526020600020905b81548152906001019060200180831161267357829003601f168201915b5050505050815260200190600101906125f8565b50505050915080805480602002602001604051908101604052809291908181526020016000905b828210156127775783829060005260206000200180546126ea90615986565b80601f016020809104026020016040519081016040528092919081815260200182805461271690615986565b80156127635780601f1061273857610100808354040283529160200191612763565b820191906000526020600020905b81548152906001019060200180831161274657829003601f168201915b5050505050815260200190600101906126cb565b50505050905094509450945094505092959194509250565b60008061279e868686866123a9565b6000818152600b880160205260409081902060138101805460ff191660011790559051919250907f9fb4e5204ac554428e5c744568b78732c229c76c0b5eaebdca7171c41366f6af906127f49084815260200190565b60405180910390a15095945050505050565b600081601001600c9054906101000a90046001600160a01b03166001600160a01b0316639b3c1e226040518163ffffffff1660e01b8152600401602060405180830381865afa15801561285d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061288191906151bc565b600a83015460098401546040516370a0823160e01b81526001600160a01b0391821660048201529116906370a0823190602401602060405180830381865afa1580156128d1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128f591906151bc565b83600a0160009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561294a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061296e91906151bc565b6129789190615937565b610df49190615937565b6000610df1612991844361299c565b5161ffff1683613614565b604080516060810182526000808252602082018190529181019190915260006129dd83604051806060016040528060408152602001615c376040913961362d565b600d8501549091506000819003612a34576040518060600160405280612a06876007015461365d565b61ffff168152602001612a1c876007015461365d565b61ffff16815260006020909101529250610df4915050565b63ffffffff8216600d8601612a4a600184615937565b81548110612a5a57612a5a615669565b600091825260209091206002909102015463ffffffff1611612aec57600d8501612a85600183615937565b81548110612a9557612a95615669565b6000918252602091829020604080516060810182526002939093029091016001015461ffff80821684526201000082041693830193909352600160201b90920463ffffffff16918101919091529250610df4915050565b8163ffffffff1685600d01600081548110612b0957612b09615669565b600091825260209091206002909102015463ffffffff161115612b3e576040518060600160405280612a06876007015461365d565b600080612b4c600184615937565b90505b81811115612c415760006002612b658484615937565b612b6f91906159c0565b612b799083615937565b9050600088600d018281548110612b9257612b92615669565b60009182526020918290206040805180820182526002909302909101805463ffffffff9081168452825160608101845260019092015461ffff80821684526201000082041683870152600160201b9004811692820192909252928201929092528051909250878216911603612c1257602001519550610df4945050505050565b805163ffffffff80881691161015612c2c57819350612c3a565b612c37600183615937565b92505b5050612b4f565b86600d018281548110612c5657612c56615669565b6000918252602091829020604080516060810182526002939093029091016001015461ffff80821684526201000082041693830193909352600160201b90920463ffffffff1691810191909152979650505050505050565b6000610df1612cbd844361299c565b6020015161ffff1683613614565b606087871015612d275760405162461bcd60e51b815260206004820152602160248201527f6c61737450726f706f73616c4964203e3d20666972737450726f706f73616c496044820152601960fa1b60648201526084016122dc565b6000612d338989615937565b612d3e906001615973565b90506000816001600160401b03811115612d5a57612d5a613c1e565b604051908082528060200260200182016040528015612de057816020015b612dcd60405180610120016040528060008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600063ffffffff168152602001606081525090565b815260200190600190039081612d785790505b509050600080612e03604051806040016040528060008152602001600081525090565b8c5b8c81116130b0578e600b01600082815260200190815260200160002093508a8015612e345750600e84015460ff165b6130a057600a84015482526011840154600160801b90046001600160401b031660208301528915612ed5576000612e7383600001518460200151613682565b9050804311612ed35760405162461bcd60e51b815260206004820152602660248201527f616c6c2070726f706f73616c73206d75737420626520646f6e65207769746820604482015265766f74696e6760d01b60648201526084016122dc565b505b600084600b015490506000856010015490506127108e61ffff1682612efa91906159e2565b612f0491906159c0565b821015612f125750506130a0565b60008a6001600160401b03811115612f2c57612f2c613c1e565b604051908082528060200260200182016040528015612f7157816020015b6040805180820190915260008082526020820152815260200190600190039081612f4a5790505b50905060005b8b81101561300b578760140160008e8e84818110612f9757612f97615669565b9050602002016020810190612fac91906151a1565b63ffffffff908116825260208083019390935260409182016000208251808401909352548082168352600160201b900416918101919091528251839083908110612ff857612ff8615669565b6020908102919091010152600101612f77565b5060408051610120810182528651815260208088015190820152908101849052600c8801546060820152600d880154608082015260a08101839052601188015463ffffffff600160201b91829004811660c08401528954919091041660e08201526101008101829052888761307f816159f9565b98508151811061309157613091615669565b60200260200101819052505050505b6130a9816159f9565b9050612e05565b50508252509a9950505050505050505050565b6000610df1836006015483613614565b606083156130e2575081611d19565b8251156130f25782518084602001fd5b8160405162461bcd60e51b81526004016122dc9190615a12565b6000808361311c866127106159e2565b61312691906159c0565b90506000620f424082856040015163ffffffff1661314491906159e2565b61314e91906159c0565b9050600081856000015161ffff166131669190615973565b9050600061317c866020015161ffff1683613698565b9050611a788188613614565b600061319484836130c3565b9050808311611d195760405163ead8241560e01b815260040160405180910390fd5b6020810151518151511415806131d3575060408101515181515114155b806131e5575060608101515181515114155b156132035760405163ccb0ce3f60e01b815260040160405180910390fd5b80515160000361322657604051630f24cd7360e01b815260040160405180910390fd5b805151600a101561324a576040516308e3b1eb60e11b815260040160405180910390fd5b50565b6001600160a01b0381166000908152600c83016020526040902054801561330557600061327a84836136a7565b9050600981600a811115613290576132906144f1565b14806132ad5750600181600a8111156132ab576132ab6144f1565b145b806132c95750600081600a8111156132c7576132c76144f1565b145b806132e55750600a81600a8111156132e3576132e36144f1565b145b15613303576040516306bee79560e01b815260040160405180910390fd5b505b505050565b600063ffffffff82111561336f5760405162461bcd60e51b815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203360448201526532206269747360d01b60648201526084016122dc565b5090565b6010860154600090819061339d9061339890600160401b900463ffffffff1643615973565b6138a0565b905060008860040154826001600160401b03166133ba9190615973565b905060008960050154826133ce9190615973565b63ffffffff808b166000818152600b8e01602090815260409091208054938a16600160201b0267ffffffffffffffff199094169092179290921781556001810180546001600160a01b03191633179055600281018b90558851805191975092935061343f9260058801920190613976565b50602080870151805161345892600688019201906139d7565b5060408601518051613474916007870191602090910190613a12565b5060608601518051613490916008870191602090910190613a64565b5060098401829055600a8401819055601084018790556134af4361330a565b60118501805463ffffffff191663ffffffff929092169190911790556134d44261330a565b6011850180546001600160401b03909516600160401b026fffffffffffffffff00000000000000001963ffffffff93909316600160201b02929092166fffffffffffffffffffffffff000000001990951694909417179092555090979650505050505050565b855483516020850151604080870151606088015160098c0154600a8d015493517f7d84a6263ae0d98d3329bd7b46bb4e8d6f98cd35a7adb45c274c8b7fd5ebd5e09761359d9763ffffffff90911696339691959094909390929091908c90615a25565b60405180910390a185546011870154600288015460405163ffffffff808616947fd9d12651716feaac10e3b79bd2960ad42ebfd84969b71a2e226ec99972a8712e946136049491909216928b926001600160401b03600160401b9091041691908b90615ac3565b60405180910390a2505050505050565b600061271061362384846159e2565b610df191906159c0565b60008163ffffffff8411156136555760405162461bcd60e51b81526004016122dc9190615a12565b509192915050565b600061ffff82111561336f5760405163555abf0160e11b815260040160405180910390fd5b60008183116136915781610df1565b5090919050565b60008183106136915781610df1565b600081836008015410156137095760405162461bcd60e51b8152602060048201526024808201527f4e6f756e7344414f3a3a73746174653a20696e76616c69642070726f706f73616044820152631b081a5960e21b60648201526084016122dc565b6000828152600b840160205260409020600e810154610100900460ff1615613735576008915050610df4565b600e81015460ff161561374c576002915050610df4565b6011810154600160401b90046001600160401b0316431161377157600a915050610df4565b80600901544311613786576000915050610df4565b80600a0154431161379b576001915050610df4565b6011810154600160801b90046001600160401b031643116137c0576009915050610df4565b6137ca8482613908565b156137d9576003915050610df4565b80600401546000036137ef576004915050610df4565b600e81015462010000900460ff161561380c576007915050610df4565b613816848261393e565b6001600160a01b031663c1a287e26040518163ffffffff1660e01b8152600401602060405180830381865afa158015613853573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061387791906151bc565b81600401546138869190615973565b4210613896576006915050610df4565b6005915050610df4565b60006001600160401b0382111561336f5760405162461bcd60e51b815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203660448201526534206269747360d01b60648201526084016122dc565b600b810154600c82015460009190811115806123a15750825461393690859063ffffffff9081169061235016565b119392505050565b601381015460009060ff1615613962575060188201546001600160a01b0316610df4565b5060098201546001600160a01b0316610df4565b8280548282559060005260206000209081019282156139cb579160200282015b828111156139cb57825182546001600160a01b0319166001600160a01b03909116178255602090920191600190910190613996565b5061336f929150613ab6565b8280548282559060005260206000209081019282156139cb579160200282015b828111156139cb5782518255916020019190600101906139f7565b828054828255906000526020600020908101928215613a58579160200282015b82811115613a585782518290613a489082615b50565b5091602001919060010190613a32565b5061336f929150613acb565b828054828255906000526020600020908101928215613aaa579160200282015b82811115613aaa5782518290613a9a9082615b50565b5091602001919060010190613a84565b5061336f929150613ae8565b5b8082111561336f5760008155600101613ab7565b8082111561336f576000613adf8282613b05565b50600101613acb565b8082111561336f576000613afc8282613b05565b50600101613ae8565b508054613b1190615986565b6000825580601f10613b21575050565b601f01602090049060005260206000209081019061324a9190613ab6565b600060208284031215613b5157600080fd5b5035919050565b815181526020808301516101e0830191613b7c908401826001600160a01b03169052565b5060408301516040830152606083015160608301526080830151608083015260a083015160a083015260c083015160c083015260e083015160e083015261010080840151818401525061012080840151818401525061014080840151613be58285018215159052565b505061016083810151151590830152610180808401511515908301526101a080840151908301526101c092830151929091019190915290565b634e487b7160e01b600052604160045260246000fd5b604051606081016001600160401b0381118282101715613c5657613c56613c1e565b60405290565b6040516101e081016001600160401b0381118282101715613c5657613c56613c1e565b60405161026081016001600160401b0381118282101715613c5657613c56613c1e565b604051601f8201601f191681016001600160401b0381118282101715613cca57613cca613c1e565b604052919050565b60006001600160401b03821115613ceb57613ceb613c1e565b5060051b60200190565b600082601f830112613d0657600080fd5b81356001600160401b03811115613d1f57613d1f613c1e565b613d32601f8201601f1916602001613ca2565b818152846020838601011115613d4757600080fd5b816020850160208301376000918101602001919091529392505050565b6001600160a01b038116811461324a57600080fd5b600082601f830112613d8a57600080fd5b81356020613d9f613d9a83613cd2565b613ca2565b82815260059290921b84018101918181019086841115613dbe57600080fd5b8286015b84811015613e505780356001600160401b0380821115613de25760008081fd5b908801906060828b03601f1901811315613dfc5760008081fd5b613e04613c34565b8784013583811115613e165760008081fd5b613e248d8a83880101613cf5565b8252506040925082840135613e3881613d64565b81890152920135908201528352918301918301613dc2565b509695505050505050565b600082601f830112613e6c57600080fd5b81356020613e7c613d9a83613cd2565b8083825260208201915060208460051b870101935086841115613e9e57600080fd5b602086015b84811015613e50578035613eb681613d64565b8352918301918301613ea3565b600082601f830112613ed457600080fd5b81356020613ee4613d9a83613cd2565b8083825260208201915060208460051b870101935086841115613f0657600080fd5b602086015b84811015613e505780358352918301918301613f0b565b600082601f830112613f3357600080fd5b81356020613f43613d9a83613cd2565b82815260059290921b84018101918181019086841115613f6257600080fd5b8286015b84811015613e505780356001600160401b03811115613f855760008081fd5b613f938986838b0101613cf5565b845250918301918301613f66565b60008060008060008060c08789031215613fba57600080fd5b86356001600160401b0380821115613fd157600080fd5b613fdd8a838b01613d79565b97506020890135915080821115613ff357600080fd5b613fff8a838b01613e5b565b9650604089013591508082111561401557600080fd5b6140218a838b01613ec3565b9550606089013591508082111561403757600080fd5b6140438a838b01613f22565b9450608089013591508082111561405957600080fd5b6140658a838b01613f22565b935060a089013591508082111561407b57600080fd5b5061408889828a01613cf5565b9150509295509295509295565b6000602082840312156140a757600080fd5b8135611d1981613d64565b60008060008060008060008789036101c08112156140cf57600080fd5b88356140da81613d64565b975060208901356140ea81613d64565b965060408901356140fa81613d64565b9550606089013561410a81613d64565b9450608089013561411a81613d64565b935060c0609f198201121561412e57600080fd5b60a089019250606061015f198201121561414757600080fd5b506101608801905092959891949750929550565b803563ffffffff8116811461416f57600080fd5b919050565b60008060008060008060c0878903121561418d57600080fd5b86356001600160401b03808211156141a457600080fd5b6141b08a838b01613e5b565b975060208901359150808211156141c657600080fd5b6141d28a838b01613ec3565b965060408901359150808211156141e857600080fd5b6141f48a838b01613f22565b9550606089013591508082111561420a57600080fd5b6142168a838b01613f22565b9450608089013591508082111561422c57600080fd5b5061423989828a01613cf5565b92505061424860a0880161415b565b90509295509295509295565b60008151808452602080850194506020840160005b8381101561428e5781516001600160a01b031687529582019590820190600101614269565b509495945050505050565b60008151808452602080850194506020840160005b8381101561428e578151875295820195908201906001016142ae565b60005b838110156142e55781810151838201526020016142cd565b50506000910152565b600081518084526143068160208601602086016142ca565b601f01601f19169290920160200192915050565b60008282518085526020808601955060208260051b8401016020860160005b8481101561436757601f198684030189526143558383516142ee565b98840198925090830190600101614339565b5090979650505050505050565b6080815260006143876080830187614254565b82810360208401526143998187614299565b905082810360408401526143ad818661431a565b90508281036060840152610f1c818561431a565b600080600080600060a086880312156143d957600080fd5b85356001600160401b03808211156143f057600080fd5b6143fc89838a01613e5b565b9650602088013591508082111561441257600080fd5b61441e89838a01613ec3565b9550604088013591508082111561443457600080fd5b61444089838a01613f22565b9450606088013591508082111561445657600080fd5b61446289838a01613f22565b9350608088013591508082111561447857600080fd5b5061448588828901613cf5565b9150509295509295909350565b803560ff8116811461416f57600080fd5b600080600080600060a086880312156144bb57600080fd5b853594506144cb60208701614492565b93506144d960408701614492565b94979396509394606081013594506080013592915050565b634e487b7160e01b600052602160045260246000fd5b60208101600b831061452957634e487b7160e01b600052602160045260246000fd5b91905290565b60008083601f84011261454157600080fd5b5081356001600160401b0381111561455857600080fd5b60208301915083602082850101111561457057600080fd5b9250929050565b6000806020838503121561458a57600080fd5b82356001600160401b038111156145a057600080fd5b6145ac8582860161452f565b90969095509350505050565b600080604083850312156145cb57600080fd5b823591506145db60208401614492565b90509250929050565b815161ffff90811682526020808401519091169082015260408083015163ffffffff169082015260608101610df4565b60008083601f84011261462657600080fd5b5081356001600160401b0381111561463d57600080fd5b6020830191508360208260051b850101111561457057600080fd5b6000806020838503121561466b57600080fd5b82356001600160401b0381111561468157600080fd5b6145ac85828601614614565b60008060008060008060c087890312156146a657600080fd5b8635955060208701356001600160401b0380821115613ff357600080fd5b6000806000604084860312156146d957600080fd5b83356001600160401b038111156146ef57600080fd5b6146fb86828701614614565b909450925050602084013561470f81613d64565b809150509250925092565b6000806000806000806060878903121561473357600080fd5b86356001600160401b038082111561474a57600080fd5b6147568a838b01614614565b9098509650602089013591508082111561476f57600080fd5b61477b8a838b01614614565b9096509450604089013591508082111561479457600080fd5b506147a189828a0161452f565b979a9699509497509295939492505050565b600080600080606085870312156147c957600080fd5b843593506147d960208601614492565b925060408501356001600160401b038111156147f457600080fd5b6148008782880161452f565b95989497509550505050565b600080600080600080600060e0888a03121561482757600080fd5b87356001600160401b038082111561483e57600080fd5b61484a8b838c01613d79565b985060208a013591508082111561486057600080fd5b61486c8b838c01613e5b565b975060408a013591508082111561488257600080fd5b61488e8b838c01613ec3565b965060608a01359150808211156148a457600080fd5b6148b08b838c01613f22565b955060808a01359150808211156148c657600080fd5b6148d28b838c01613f22565b945060a08a01359150808211156148e857600080fd5b506148f58a828b01613cf5565b92505061490460c0890161415b565b905092959891949750929550565b60008060008060006080868803121561492a57600080fd5b8535945061493a60208701614492565b935060408601356001600160401b0381111561495557600080fd5b6149618882890161452f565b909450925061497490506060870161415b565b90509295509295909350565b60008060006060848603121561499557600080fd5b833592506149a560208501614492565b91506149b36040850161415b565b90509250925092565b600080600080600080600080610100898b0312156149d957600080fd5b8835975060208901356001600160401b03808211156149f757600080fd5b614a038c838d01613d79565b985060408b0135915080821115614a1957600080fd5b614a258c838d01613e5b565b975060608b0135915080821115614a3b57600080fd5b614a478c838d01613ec3565b965060808b0135915080821115614a5d57600080fd5b614a698c838d01613f22565b955060a08b0135915080821115614a7f57600080fd5b614a8b8c838d01613f22565b945060c08b0135915080821115614aa157600080fd5b614aad8c838d01613cf5565b935060e08b0135915080821115614ac357600080fd5b50614ad08b828c01613cf5565b9150509295985092959890939650565b803561ffff8116811461416f57600080fd5b600080600083850360a0811215614b0857600080fd5b84359350602085013592506060603f1982011215614b2557600080fd5b50614b2e613c34565b614b3a60408601614ae0565b8152614b4860608601614ae0565b6020820152614b596080860161415b565b6040820152809150509250925092565b63ffffffff81511682526020810151613305602084018261ffff8082511683528060208301511660208401525063ffffffff60408201511660408301525050565b6020808252825182820181905260009190848201906040850190845b81811015614bec57614bd9838551614b69565b9284019260809290920191600101614bc6565b50909695505050505050565b801515811461324a57600080fd5b600080600080600080600060c0888a031215614c2157600080fd5b8735965060208801359550614c3860408901614ae0565b94506060880135614c4881614bf8565b93506080880135614c5881614bf8565b925060a08801356001600160401b03811115614c7357600080fd5b614c7f8a828b01614614565b989b979a50959850939692959293505050565b60008151808452602080850194506020840160005b8381101561428e578151805163ffffffff908116895290840151168388015260409096019590820190600101614ca7565b600060208083018184528085518083526040925060408601915060408160051b87010184880160005b83811015614d9157888303603f1901855281518051845287810151888501528681015187850152606080820151908501526080808201519085015260a0808201519085015260c0808201519085015260e08082015163ffffffff16908501526101009081015161012091850182905290614d7d81860183614c92565b968901969450505090860190600101614d01565b509098975050505050505050565b60808101610df48284614b69565b602081526000610df16020830184614254565b600080600080600060608688031215614dd857600080fd5b8535945060208601356001600160401b0380821115614df657600080fd5b614e0289838a0161452f565b90965094506040880135915080821115614e1b57600080fd5b50614e288882890161452f565b969995985093965092949392505050565b600080600080600080600060e0888a031215614e5457600080fd5b8735965060208801356001600160401b0380821115614e7257600080fd5b614e7e8b838c01613e5b565b975060408a0135915080821115614e9457600080fd5b614ea08b838c01613ec3565b965060608a0135915080821115614eb657600080fd5b614ec28b838c01613f22565b955060808a0135915080821115614ed857600080fd5b614ee48b838c01613f22565b945060a08a0135915080821115614efa57600080fd5b614f068b838c01613cf5565b935060c08a0135915080821115614f1c57600080fd5b50614f298a828b01613cf5565b91505092959891949750929550565b60008060408385031215614f4b57600080fd5b823591506020830135614f5d81613d64565b809150509250929050565b602081528151602082015260006020830151614f8f60408401826001600160a01b03169052565b506040830151606083015260608301516080830152608083015160a083015260a083015160c083015260c083015160e083015260e08301516101008181850152808501519150506101208181850152808501519150506101408181850152808501519150506101606150048185018315159052565b84015190506101806150198482018315159052565b84015190506101a061502e8482018315159052565b8401516101c0848101919091528401516101e08085019190915284015161026061020080860182905291925090615069610280860184614254565b9086015161022086810191909152860151610240808701919091529095015115159301929092525090919050565b805161416f81613d64565b805161416f81614bf8565b60006101e082840312156150c057600080fd5b6150c8613c5c565b825181526150d860208401615097565b602082015260408301516040820152606083015160608201526080830151608082015260a083015160a082015260c083015160c082015260e083015160e082015261010080840151818301525061012080840151818301525061014061513f8185016150a2565b908201526101606151518482016150a2565b908201526101806151638482016150a2565b908201526101a083810151908201526101c0928301519281019290925250919050565b60006020828403121561519857600080fd5b610df182614ae0565b6000602082840312156151b357600080fd5b610df18261415b565b6000602082840312156151ce57600080fd5b5051919050565b6000602082840312156151e757600080fd5b8151600b8110611d1957600080fd5b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b8381526040602082015260006152396040830184866151f6565b95945050505050565b81835260006001600160fb1b0383111561525b57600080fd5b8260051b80836020870137939093016020019392505050565b838152604060208201526000615239604083018486615242565b87815286602082015260e0604082015260006152ad60e0830188614254565b82810360608401526152bf8188614299565b905082810360808401526152d3818761431a565b905082810360a08401526152e7818661431a565b905082810360c08401526152fb81856142ee565b9a9950505050505050505050565b848152606060208201526000615323606083018587615242565b905060018060a01b038316604083015295945050505050565b87815260806020820152600061535660808301888a615242565b8281036040840152615369818789615242565b905082810360608401526152fb8185876151f6565b86815285602082015260ff8516604082015260a0606082015260006153a760a0830185876151f6565b905063ffffffff83166080830152979650505050505050565b600082825180855260208086019550808260051b84010181860160005b8481101561436757601f19868403018952815160608151818652615403828701826142ee565b838801516001600160a01b0316878901526040938401519390960192909252505097830197908301906001016153dd565b60008282518085526020808601955060208260051b8401016020860160005b8481101561436757601f1986840301895261546f8383516142ee565b98840198925090830190600101615453565b8051608080845281519084018190526000916020919082019060a0860190845b818110156154c65783516001600160a01b0316835292840192918401916001016154a1565b50506020850151925085810360208701526154e18184614299565b92505050604083015184820360408601526154fc8282615434565b915050606083015184820360608601526152398282615434565b85815260a06020820152600061552f60a08301876153c0565b82810360408401526155418187615481565b9050828103606084015261555581866142ee565b91505063ffffffff831660808301529695505050505050565b6000806040838503121561558157600080fd5b825161558c81613d64565b6020840151909250614f5d81613d64565b85815284602082015260ff84166040820152608060608201526000610f1c6080830184866151f6565b86815285602082015260c0604082015260006155e560c08301876153c0565b82810360608401526155f78187615481565b9050828103608084015261560b81866142ee565b905082810360a084015261561f81856142ee565b9998505050505050505050565b8381526020808201849052825161ffff9081166040808501919091529184015116606083015282015163ffffffff16608082015260a081016123a1565b634e487b7160e01b600052603260045260246000fd5b86815285602082015260806040820152600061569f6080830186886151f6565b828103606084015261561f8185876151f6565b60006101008a83528960208401528060408401526156d28184018a614254565b905082810360608401526156e68189614299565b905082810360808401526156fa818861431a565b905082810360a084015261570e818761431a565b905082810360c084015261572281866142ee565b905082810360e084015261573681856142ee565b9b9a5050505050505050505050565b600082601f83011261575657600080fd5b81516020615766613d9a83613cd2565b8083825260208201915060208460051b87010193508684111561578857600080fd5b602086015b84811015613e505780516157a081613d64565b835291830191830161578d565b6000602082840312156157bf57600080fd5b81516001600160401b03808211156157d657600080fd5b9083019061026082860312156157eb57600080fd5b6157f3613c7f565b8251815261580360208401615097565b602082015260408301516040820152606083015160608201526080830151608082015260a083015160a082015260c083015160c082015260e083015160e082015261010080840151818301525061012080840151818301525061014061586a8185016150a2565b9082015261016061587c8482016150a2565b9082015261018061588e8482016150a2565b908201526101a083810151908201526101c080840151908201526101e080840151838111156158bc57600080fd5b6158c888828701615745565b91830191909152506102008381015190820152610220808401519082015261024091506158f68284016150a2565b91810191909152949350505050565b600082516159178184602087016142ca565b9190910192915050565b634e487b7160e01b600052601160045260246000fd5b81810381811115610df457610df4615921565b60006020828403121561595c57600080fd5b81516001600160601b0381168114611d1957600080fd5b80820180821115610df457610df4615921565b600181811c9082168061599a57607f821691505b6020821081036159ba57634e487b7160e01b600052602260045260246000fd5b50919050565b6000826159dd57634e487b7160e01b600052601260045260246000fd5b500490565b8082028115828204841417610df457610df4615921565b600060018201615a0b57615a0b615921565b5060010190565b602081526000610df160208301846142ee565b63ffffffff8a1681526001600160a01b038916602082015261012060408201819052600090615a568382018b614254565b90508281036060840152615a6a818a614299565b90508281036080840152615a7e818961431a565b905082810360a0840152615a92818861431a565b90508560c08401528460e0840152828103610100840152615ab381856142ee565b9c9b505050505050505050505050565b63ffffffff8616815260a060208201526000615ae260a0830187614254565b6001600160401b0395909516604083015250606081019290925260809091015292915050565b601f821115613305576000816000526020600020601f850160051c81016020861015615b315750805b601f850160051c820191505b818110156116ea57828155600101615b3d565b81516001600160401b03811115615b6957615b69613c1e565b615b7d81615b778454615986565b84615b08565b602080601f831160018114615bb25760008415615b9a5750858301515b600019600386901b1c1916600185901b1785556116ea565b600085815260208120601f198616915b82811015615be157888601518255948401946001909101908401615bc2565b5085821015615bff5787850151600019600388901b60f8161c191681555b5050505050600190811b0190555056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c65644e6f756e7344414f3a3a67657444796e616d696351756f72756d506172616d7341743a20626c6f636b206e756d62657220657863656564732033322062697473a26469706673582212209727ca74986184ed031177b5021a46512e6f96c4c604da0c453d87c2106b183b64736f6c63430008170033", + "nonce": "0x145", + "chainId": "0xaa36a7", + "accessList": null, + "type": null + }, + "additionalContracts": [], + "isFixedGasLimit": false + } + ], + "receipts": [ + { + "status": "0x1", + "cumulativeGasUsed": "0xf8e65e", + "logs": [], + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "type": "0x2", + "transactionHash": "0x992ca4f70c62a5af2707e4187f7873a56f96ad58827c7e695370cd0bbb18411c", + "transactionIndex": "0x51", + "blockHash": "0x89d5d78ed4b0195d325d38c86e54056938847609489e1c0c2ef5756242a80e07", + "blockNumber": "0x57e113", + "gasUsed": "0x1e623e", + "effectiveGasPrice": "0xee7dafe", + "from": "0xad36c32f3c28a9214adcf50a09998de1d3b0ee06", + "to": null, + "contractAddress": "0x02e813dbeaddefe9921f4a2093206aefef4453d6" + }, + { + "status": "0x1", + "cumulativeGasUsed": "0xfbcd95", + "logs": [], + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "type": "0x2", + "transactionHash": "0x6365742b0e5dba31c0c11d73a1998fc4c5fe197a57f2c1e27cec0bea4f285184", + "transactionIndex": "0x52", + "blockHash": "0x89d5d78ed4b0195d325d38c86e54056938847609489e1c0c2ef5756242a80e07", + "blockNumber": "0x57e113", + "gasUsed": "0x2e737", + "effectiveGasPrice": "0xee7dafe", + "from": "0xad36c32f3c28a9214adcf50a09998de1d3b0ee06", + "to": null, + "contractAddress": "0x970583ad744c3f73eafc7f25591373ba17bdd286" + }, + { + "status": "0x1", + "cumulativeGasUsed": "0x10cb84e", + "logs": [], + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "type": "0x2", + "transactionHash": "0xc0328521eb096b2b664efd70f89a555d94c03a0ec48c29bcdd4b16b31a4d1135", + "transactionIndex": "0x53", + "blockHash": "0x89d5d78ed4b0195d325d38c86e54056938847609489e1c0c2ef5756242a80e07", + "blockNumber": "0x57e113", + "gasUsed": "0x10eab9", + "effectiveGasPrice": "0xee7dafe", + "from": "0xad36c32f3c28a9214adcf50a09998de1d3b0ee06", + "to": null, + "contractAddress": "0x3f08ce1a659c34737d1a1aae437bf5a99a1857be" + }, + { + "status": "0x1", + "cumulativeGasUsed": "0x14a4293", + "logs": [], + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "type": "0x2", + "transactionHash": "0xacd69dc1124b78c0e1941053a221a43cd0c3751eada70aee92fa8cac7e79963b", + "transactionIndex": "0x54", + "blockHash": "0x89d5d78ed4b0195d325d38c86e54056938847609489e1c0c2ef5756242a80e07", + "blockNumber": "0x57e113", + "gasUsed": "0x3d8a45", + "effectiveGasPrice": "0xee7dafe", + "from": "0xad36c32f3c28a9214adcf50a09998de1d3b0ee06", + "to": null, + "contractAddress": "0x81ede38efc867818bf77978514f5dca76c20a050" + }, + { + "status": "0x1", + "cumulativeGasUsed": "0x1612ced", + "logs": [], + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "type": "0x2", + "transactionHash": "0xd8e5ad5005fa8e231687ee17d418d98e0bf39f486d83f80aec0d71fdff72999a", + "transactionIndex": "0x55", + "blockHash": "0x89d5d78ed4b0195d325d38c86e54056938847609489e1c0c2ef5756242a80e07", + "blockNumber": "0x57e113", + "gasUsed": "0x16ea5a", + "effectiveGasPrice": "0xee7dafe", + "from": "0xad36c32f3c28a9214adcf50a09998de1d3b0ee06", + "to": null, + "contractAddress": "0x30656985039923eaa1ebb968fe84a1277581f602" + }, + { + "status": "0x1", + "cumulativeGasUsed": "0x1b02ab9", + "logs": [], + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "type": "0x2", + "transactionHash": "0xd534b73edd763c42dd5102fb7ec5b3c7b45936edc12dde860bdd8b5c87cb257a", + "transactionIndex": "0x56", + "blockHash": "0x89d5d78ed4b0195d325d38c86e54056938847609489e1c0c2ef5756242a80e07", + "blockNumber": "0x57e113", + "gasUsed": "0x4efdcc", + "effectiveGasPrice": "0xee7dafe", + "from": "0xad36c32f3c28a9214adcf50a09998de1d3b0ee06", + "to": null, + "contractAddress": "0x017b4fd1a03308df03cb9a03a303fe9e6bc8ab7d" + } + ], + "libraries": [ + "contracts/governance/NounsDAOAdmin.sol:NounsDAOAdmin:0x02e813dbeaDDEFE9921f4a2093206AefeF4453d6", + "contracts/governance/NounsDAODynamicQuorum.sol:NounsDAODynamicQuorum:0x970583ad744c3F73EAfc7f25591373bA17BDD286", + "contracts/governance/NounsDAOProposals.sol:NounsDAOProposals:0x81EDe38Efc867818BF77978514f5dCa76C20A050", + "contracts/governance/NounsDAOVotes.sol:NounsDAOVotes:0x30656985039923EAa1eBb968fe84A1277581f602", + "contracts/governance/fork/NounsDAOFork.sol:NounsDAOFork:0x3F08ce1a659c34737D1a1aae437bF5A99A1857be" + ], + "pending": [], + "returns": { + "daoLogic": { + "internal_type": "contract NounsDAOLogicV4", + "value": "0x017B4Fd1a03308Df03CB9a03A303FE9E6bC8aB7d" + } + }, + "timestamp": 1713864124, + "chain": 11155111, + "commit": "82b8d911" +} \ No newline at end of file diff --git a/packages/nouns-contracts/broadcast/DeployDAOLogicOptimized.s.sol/11155111/run-latest.json b/packages/nouns-contracts/broadcast/DeployDAOLogicOptimized.s.sol/11155111/run-latest.json new file mode 100644 index 0000000000..c7e6fae0cc --- /dev/null +++ b/packages/nouns-contracts/broadcast/DeployDAOLogicOptimized.s.sol/11155111/run-latest.json @@ -0,0 +1,245 @@ +{ + "transactions": [ + { + "hash": "0x992ca4f70c62a5af2707e4187f7873a56f96ad58827c7e695370cd0bbb18411c", + "transactionType": "CREATE", + "contractName": "NounsDAOAdmin", + "contractAddress": "0x02e813dbeaddefe9921f4a2093206aefef4453d6", + "function": null, + "arguments": null, + "transaction": { + "from": "0xad36c32f3c28a9214adcf50a09998de1d3b0ee06", + "to": null, + "gas": "0x277cd7", + "value": null, + "input": "0x61230c61003a600b82828239805160001a60731461002d57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600436106102315760003560e01c8063a267a3d11161013a578063db725e17116100c2578063e9c714f211610086578063e9c714f21461052f578063ec91deda14610544578063ee186559146104a2578063f5f4714c14610564578063fd22b60a146104dc57600080fd5b8063db725e17146104d3578063dfcda1ef146104dc578063e2560772146104e6578063e5eb5abf14610506578063e7951bb91461052657600080fd5b8063c10eb14d11610109578063c10eb14d14610478578063c82fbd0814610371578063cbff4a13146104a2578063ccfa51c9146104ab578063d3f662e1146104b357600080fd5b8063a267a3d114610419578063a78b5f1a14610423578063b71d1a0c14610443578063bf7a29631461046357600080fd5b80632df01bdb116101bd57806374b157b81161018c57806374b157b8146103795780637a3da69114610399578063842e4dae146103b95780639547aecb146103d957806397d048e5146103f957600080fd5b80632df01bdb1461031157806344697f981461033157806350196db31461035157806351e313e01461037157600080fd5b80631e7b5d3a116102045780631e7b5d3a146102ad57806326e6dcb0146102c957806327126e67146102d25780632b5ca189146102dc5780632cfc81c6146102fc57600080fd5b806306ef9d36146102365780630dc0ce3f146102585780630ea2d98c1461026d5780631dfb1b5a1461028d575b600080fd5b81801561024257600080fd5b50610256610251366004611ef2565b610584565b005b81801561026457600080fd5b506102566105f2565b81801561027957600080fd5b50610256610288366004611ef2565b610624565b81801561029957600080fd5b506102566102a8366004611ef2565b610715565b6102b66103e881565b6040519081526020015b60405180910390f35b6102b661177081565b6102b66212750081565b8180156102e857600080fd5b506102566102f7366004611f24565b6107f6565b81801561030857600080fd5b50610256610891565b81801561031d57600080fd5b5061025661032c366004611f5d565b610986565b81801561033d57600080fd5b5061025661034c366004611f78565b610a2c565b81801561035d57600080fd5b5061025661036c366004611fcd565b610ad3565b6102b6600181565b81801561038557600080fd5b50610256610394366004611f24565b610c67565b8180156103a557600080fd5b506102566103b4366004611fcd565b610d28565b8180156103c557600080fd5b506102566103d4366004611ef2565b610ecc565b8180156103e557600080fd5b506102566103f4366004612034565b610f82565b81801561040557600080fd5b50610256610414366004611ef2565b610fb8565b6102b66202a30081565b81801561042f57600080fd5b5061025661043e3660046120a7565b6110a6565b81801561044f57600080fd5b5061025661045e366004611f5d565b611129565b81801561046f57600080fd5b506102566111a7565b81801561048457600080fd5b5061048d611262565b604080519283529015156020830152016102c0565b6102b661c4e081565b6102b660c881565b8180156104bf57600080fd5b506102566104ce366004611f5d565b611320565b6102b6611c2081565b6102b6620189c081565b8180156104f257600080fd5b50610256610501366004611f24565b6113b7565b81801561051257600080fd5b50610256610521366004611f24565b611436565b6102b66107d081565b81801561053b57600080fd5b506102566114ef565b81801561055057600080fd5b5061025661055f3660046120e9565b611605565b81801561057057600080fd5b5061025661057f366004611f5d565b6117de565b6000546001600160a01b031633146105af57604051633057182d60e21b815260040160405180910390fd5b7f8008239436e26bac1476fd338f5a2ec6415794efc1afa04145a4845547f37adc60006017015460408051918252602082018490520160405180910390a1601755565b6000546001600160a01b0316331461061d57604051633057182d60e21b815260040160405180910390fd5b6000601955565b6000546001600160a01b0316331461064f57604051633057182d60e21b815260040160405180910390fd5b611c2081101580156106645750620189c08111155b6106cf5760405162461bcd60e51b815260206004820152603160248201527f4e6f756e7344414f3a3a5f736574566f74696e67506572696f643a20696e76616044820152701b1a59081d9bdd1a5b99c81c195c9a5bd9607a1b60648201526084015b60405180910390fd5b600580549082905560408051828152602081018490527f7e3f7f0708a84de9203036abaa450dccc85ad5ff52f78c170f3edb55cf5e882891015b60405180910390a15050565b6000546001600160a01b0316331461074057604051633057182d60e21b815260040160405180910390fd5b600181101580156107545750620189c08111155b6107b85760405162461bcd60e51b815260206004820152602f60248201527f4e6f756e7344414f3a3a5f736574566f74696e6744656c61793a20696e76616c60448201526e696420766f74696e672064656c617960881b60648201526084016106c6565b600480549082905560408051828152602081018490527fc565b045403dc03c2eea82b81a0465edad9e2e7fc4d97e11421c209da93d7a939101610709565b6000546001600160a01b0316331461082157604051633057182d60e21b815260040160405180910390fd5b600061082f43825b9061185c565b60408101805163ffffffff851690915290915061084b82611b73565b6040805163ffffffff8084168252851660208201527f5e3adb1066359dafa23c629f245d93543856115700821dcb4debc416f393c46991015b60405180910390a1505050565b6000600e01546001600160a01b031633146108bf57604051631bd9bb1b60e31b815260040160405180910390fd5b600354600e546040517fc5644f3588a066b15dcf6b636b74aadca57cfaccf608d9de7d8786364b7a8d0292610902926001600160a01b0391821692911690612123565b60405180910390a1600e546001600160a01b031660005b60030180546001600160a01b0319166001600160a01b03928316179055600e546040517f7ad92e57a52c4e3e83ba624622b14e3a5efa0160dd6f9a7975c43ea66bad79ea9261096c921690600090612123565b60405180910390a1600e80546001600160a01b0319169055565b6000546001600160a01b031633146109b157604051633057182d60e21b815260040160405180910390fd5b7ff890a07a97cb2de686a62235272191a50a2113c4fda17ce6ab5ffd20a06d56d36000601001546040516109f791600160601b90046001600160a01b0316908490612123565b60405180910390a1601080546001600160a01b03909216600160601b026bffffffffffffffffffffffff909216919091179055565b6000546001600160a01b03163314610a5757604051633057182d60e21b815260040160405180910390fd5b600980546001600160a01b038086166001600160a01b0319928316811790935560188054868316908416811790915560008054928616929093168217909255604080519384526020840192909252908201527f13c01549e11ee7e3b2c89b08a2fd55875d85aaf1aa217bf18d1ab0f88f959d2490606001610884565b6000546001600160a01b03163314610afe57604051633057182d60e21b815260040160405180910390fd5b6000610b0a4382610829565b90506117708261ffff161115610b885760405162461bcd60e51b815260206004820152603d60248201527f4e6f756e7344414f3a3a5f7365744d617851756f72756d566f7465734250533a60448201527f20696e76616c6964206d61782071756f72756d20766f7465732062707300000060648201526084016106c6565b805161ffff80841691161115610c155760405162461bcd60e51b815260206004820152604660248201527f4e6f756e7344414f3a3a5f7365744d617851756f72756d566f7465734250533a60448201527f206d696e2071756f72756d20766f7465732062707320677265617465722074686064820152650c2dc40dac2f60d31b608482015260a4016106c6565b60208101805161ffff8416909152610c2c82611b73565b6040805161ffff8084168252851660208201527f4bfb1235074b38f02e5cf8ba90f535905417c196a12654f65ee0584512d706429101610884565b6000546001600160a01b03163314610c9257604051633057182d60e21b815260040160405180910390fd5b61c4e08163ffffffff161115610cbb576040516388a79ca760e01b815260040160405180910390fd5b6010805463ffffffff838116680100000000000000008181026bffffffff0000000000000000198516179094556040805194909304919091168084526020840191909152917fd185da00ceb738d5e65ef6936975bcb81fe742adc63d901592003d7bc22f4dfa9101610709565b6000546001600160a01b03163314610d5357604051633057182d60e21b815260040160405180910390fd5b6000610d5f4382610829565b905060c88261ffff1610158015610d7c57506107d08261ffff1611155b610dee5760405162461bcd60e51b815260206004820152603d60248201527f4e6f756e7344414f3a3a5f7365744d696e51756f72756d566f7465734250533a60448201527f20696e76616c6964206d696e2071756f72756d20766f7465732062707300000060648201526084016106c6565b806020015161ffff168261ffff161115610e7f5760405162461bcd60e51b815260206004820152604660248201527f4e6f756e7344414f3a3a5f7365744d696e51756f72756d566f7465734250533a60448201527f206d696e2071756f72756d20766f7465732062707320677265617465722074686064820152650c2dc40dac2f60d31b608482015260a4016106c6565b805161ffff83168252610e9182611b73565b6040805161ffff8084168252851660208201527ffaeebe30d875e399189096ea49fea81bd41fe6dfc86ad3550639063219e607789101610884565b6000546001600160a01b03163314610ef757604051633057182d60e21b815260040160405180910390fd5b62127500811115610f1b57604051637762590b60e01b815260040160405180910390fd5b6202a300811015610f3f57604051633430477560e11b815260040160405180910390fd5b7ffa0345f15af4cde74f214a8800528bd12cb260c12d8669007af35d869cb6877360006016015460408051918252602082018490520160405180910390a1601655565b610f8b86610986565b610f94856117de565b610f9e84846110a6565b610fa782610ecc565b610fb081610584565b505050505050565b6000546001600160a01b03163314610fe357604051633057182d60e21b815260040160405180910390fd5b60018110158015610ff657506103e88111155b6110685760405162461bcd60e51b815260206004820152603f60248201527f4e6f756e7344414f3a3a5f73657450726f706f73616c5468726573686f6c643a60448201527f20696e76616c69642070726f706f73616c207468726573686f6c64206270730060648201526084016106c6565b600680549082905560408051828152602081018490527ffc216faa269bf440fb06aa490693f409461bde9cdcb949c7b9f2cb79589e7a589101610709565b6000546001600160a01b031633146110d157604051633057182d60e21b815260040160405180910390fd5b6110db8282611d61565b6040517f6158953ac4c84a0a8642793ade32098d1ecd12702db9ce2eb7c72c4463a8fb0790611110906012908590859061213d565b60405180910390a161112460128383611e83565b505050565b6000546001600160a01b0316331461115457604051633057182d60e21b815260040160405180910390fd5b600180546001600160a01b038381166001600160a01b03198316179092556040519116907fca4f2f25d0898edd99413412fb94012f9e54ec8142f9b093e7720646a95b16a9906107099083908590612123565b6000600301546001600160a01b031633146112125760405162461bcd60e51b815260206004820152602560248201527f4e6f756e7344414f3a3a5f6275726e5665746f506f7765723a207665746f6572604482015264206f6e6c7960d81b60648201526084016106c6565b7fc5644f3588a066b15dcf6b636b74aadca57cfaccf608d9de7d8786364b7a8d02600060030154604051611252916001600160a01b031690600090612123565b60405180910390a1600080610919565b60008080546001600160a01b0316331461128f57604051633057182d60e21b815260040160405180910390fd5b6040514790600090339083908381818185875af1925050503d80600081146112d3576040519150601f19603f3d011682016040523d82523d6000602084013e6112d8565b606091505b50506040805184815282151560208201529192507f2aeb20ed0ead73e7bc740154a0b979547bc9e00691d84a700e6454ada9fe4679910160405180910390a190925090509091565b6000600301546001600160a01b0316331461134e57604051631387214760e01b815260040160405180910390fd5b7f7ad92e57a52c4e3e83ba624622b14e3a5efa0160dd6f9a7975c43ea66bad79ea6000600e015460405161138d916001600160a01b0316908490612123565b60405180910390a1600e80546001600160a01b0319166001600160a01b0392909216919091179055565b6000546001600160a01b031633146113e257604051633057182d60e21b815260040160405180910390fd5b6010805463ffffffff83811663ffffffff1983168117909355604080519190921680825260208201939093527f581878c50ce0b9e3ff58adfe29b7a807191bef3c1623340a0ad1d0d8433ebf869101610709565b6000546001600160a01b0316331461146157604051633057182d60e21b815260040160405180910390fd5b61c4e08163ffffffff16111561148a5760405163024c1d4b60e31b815260040160405180910390fd5b6010805463ffffffff83811664010000000081810267ffffffff00000000198516179094556040805194909304919091168084526020840191909152917ff860ba522a6e820ac6577b201d9314604a19ad2e264913d8361821e3659568db9101610709565b6000600101546001600160a01b03163314801561150b57503315155b61156a5760405162461bcd60e51b815260206004820152602a60248201527f4e6f756e7344414f3a3a5f61636365707441646d696e3a2070656e64696e672060448201526961646d696e206f6e6c7960b01b60648201526084016106c6565b60008054600180546001600160a01b03198084166001600160a01b03838116918217909655911690915560405192909116917ff9ffabca9c8276e99321725bcb43fb076a6c66a54b7f21c4e8146d8519b417dc906115cb9084908490612123565b60405180910390a17fca4f2f25d0898edd99413412fb94012f9e54ec8142f9b093e7720646a95b16a9816000604051610709929190612123565b6000546001600160a01b0316331461163057604051633057182d60e21b815260040160405180910390fd5b60c88361ffff16108061164857506107d08361ffff16115b156116665760405163db8a74af60e01b815260040160405180910390fd5b6117708261ffff16111561168d5760405163143abf4360e21b815260040160405180910390fd5b8161ffff168361ffff1611156116b6576040516362c564d560e11b815260040160405180910390fd5b60006116c24382610829565b9050600060405180606001604052808661ffff1681526020018561ffff1681526020018463ffffffff1681525090506116fa81611b73565b815181516040805161ffff93841681529290911660208301527ffaeebe30d875e399189096ea49fea81bd41fe6dfc86ad3550639063219e60778910160405180910390a17f4bfb1235074b38f02e5cf8ba90f535905417c196a12654f65ee0584512d706428260200151826020015160405161178792919061ffff92831681529116602082015260400190565b60405180910390a160408083015182820151825163ffffffff9283168152911660208201527f5e3adb1066359dafa23c629f245d93543856115700821dcb4debc416f393c469910160405180910390a15050505050565b6000546001600160a01b0316331461180957604051633057182d60e21b815260040160405180910390fd5b601180546001600160a01b038381166001600160a01b03198316179092556040519116907f5f317d96631add203c522c8ecc74fd6144c936367e2205ac922331fb12b670b4906107099083908590612123565b6040805160608101825260008082526020820181905291810191909152600061189d8360405180606001604052806040815260200161229760409139611e2a565b600d85015490915060008190036118f45760405180606001604052806118c68760070154611e5a565b61ffff1681526020016118dc8760070154611e5a565b61ffff16815260006020909101529250611b6d915050565b63ffffffff8216600d860161190a6001846121e9565b8154811061191a5761191a6121fc565b600091825260209091206002909102015463ffffffff16116119ad57600d85016119456001836121e9565b81548110611955576119556121fc565b6000918252602091829020604080516060810182526002939093029091016001015461ffff8082168452620100008204169383019390935264010000000090920463ffffffff16918101919091529250611b6d915050565b8163ffffffff1685600d016000815481106119ca576119ca6121fc565b600091825260209091206002909102015463ffffffff1611156119ff5760405180606001604052806118c68760070154611e5a565b600080611a0d6001846121e9565b90505b81811115611b035760006002611a2684846121e9565b611a309190612212565b611a3a90836121e9565b9050600088600d018281548110611a5357611a536121fc565b60009182526020918290206040805180820182526002909302909101805463ffffffff9081168452825160608101845260019092015461ffff808216845262010000820416838701526401000000009004811692820192909252928201929092528051909250878216911603611ad457602001519550611b6d945050505050565b805163ffffffff80881691161015611aee57819350611afc565b611af96001836121e9565b92505b5050611a10565b86600d018281548110611b1857611b186121fc565b6000918252602091829020604080516060810182526002939093029091016001015461ffff8082168452620100008204169383019390935264010000000090920463ffffffff16918101919091529450505050505b92915050565b6000611bb4436040518060400160405280601c81526020017f626c6f636b206e756d6265722065786365656473203332206269747300000000815250611e2a565b600d549091508015801590611c01575063ffffffff8216600d611bd86001846121e9565b81548110611be857611be86121fc565b600091825260209091206002909102015463ffffffff16145b15611c8e5782600d611c146001846121e9565b81548110611c2457611c246121fc565b60009182526020918290208351600160029093029091019190910180549284015160409094015163ffffffff166401000000000267ffffffff000000001961ffff958616620100000263ffffffff1990951695909316949094179290921716919091179055505050565b5060408051808201825263ffffffff92831681526020808201948552600d805460018101825560009190915291517fd7b6990105719101dabeb77144f2a3385c8033acd3af97e9423a695e81ad1eb56002909302928301805491861663ffffffff19928316179055945180517fd7b6990105719101dabeb77144f2a3385c8033acd3af97e9423a695e81ad1eb690930180549282015191909401519094166401000000000267ffffffff000000001961ffff95861662010000029290961694909216939093179290921792909216179055565b6000819003611d6e575050565b60005b611d7c6001836121e9565b811015611124576000611d90826001612234565b90505b82811015611e2157838382818110611dad57611dad6121fc565b9050602002016020810190611dc29190611f5d565b6001600160a01b0316848484818110611ddd57611ddd6121fc565b9050602002016020810190611df29190611f5d565b6001600160a01b031603611e1957604051630254983f60e41b815260040160405180910390fd5b600101611d93565b50600101611d71565b60008163ffffffff841115611e525760405162461bcd60e51b81526004016106c69190612247565b509192915050565b600061ffff821115611e7f5760405163555abf0160e11b815260040160405180910390fd5b5090565b828054828255906000526020600020908101928215611ed6579160200282015b82811115611ed65781546001600160a01b0319166001600160a01b03843516178255602090920191600190910190611ea3565b50611e7f9291505b80821115611e7f5760008155600101611ede565b600060208284031215611f0457600080fd5b5035919050565b803563ffffffff81168114611f1f57600080fd5b919050565b600060208284031215611f3657600080fd5b611f3f82611f0b565b9392505050565b80356001600160a01b0381168114611f1f57600080fd5b600060208284031215611f6f57600080fd5b611f3f82611f46565b600080600060608486031215611f8d57600080fd5b611f9684611f46565b9250611fa460208501611f46565b9150611fb260408501611f46565b90509250925092565b803561ffff81168114611f1f57600080fd5b600060208284031215611fdf57600080fd5b611f3f82611fbb565b60008083601f840112611ffa57600080fd5b50813567ffffffffffffffff81111561201257600080fd5b6020830191508360208260051b850101111561202d57600080fd5b9250929050565b60008060008060008060a0878903121561204d57600080fd5b61205687611f46565b955061206460208801611f46565b9450604087013567ffffffffffffffff81111561208057600080fd5b61208c89828a01611fe8565b979a9699509760608101359660809091013595509350505050565b600080602083850312156120ba57600080fd5b823567ffffffffffffffff8111156120d157600080fd5b6120dd85828601611fe8565b90969095509350505050565b6000806000606084860312156120fe57600080fd5b61210784611fbb565b925061211560208501611fbb565b9150611fb260408501611f0b565b6001600160a01b0392831681529116602082015260400190565b6000604082016040835280865480835260608501915087600052602092508260002060005b828110156121875781546001600160a01b031684529284019260019182019101612162565b505050838103828501528481528590820160005b868110156121c7576001600160a01b036121b484611f46565b168252918301919083019060010161219b565b50979650505050505050565b634e487b7160e01b600052601160045260246000fd5b81810381811115611b6d57611b6d6121d3565b634e487b7160e01b600052603260045260246000fd5b60008261222f57634e487b7160e01b600052601260045260246000fd5b500490565b80820180821115611b6d57611b6d6121d3565b60006020808352835180602085015260005b8181101561227557858101830151858201604001528201612259565b506000604082860101526040601f19601f830116850101925050509291505056fe4e6f756e7344414f3a3a67657444796e616d696351756f72756d506172616d7341743a20626c6f636b206e756d62657220657863656564732033322062697473a2646970667358221220c5e5aef6847a19b009419ec27b21f32c87b71c941e50267d3a1a5da2521c32ae64736f6c63430008170033", + "nonce": "0x140", + "chainId": "0xaa36a7", + "accessList": null, + "type": null + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x6365742b0e5dba31c0c11d73a1998fc4c5fe197a57f2c1e27cec0bea4f285184", + "transactionType": "CREATE", + "contractName": "NounsDAODynamicQuorum", + "contractAddress": "0x970583ad744c3f73eafc7f25591373ba17bdd286", + "function": null, + "arguments": null, + "transaction": { + "from": "0xad36c32f3c28a9214adcf50a09998de1d3b0ee06", + "to": null, + "gas": "0x3c5f4", + "value": null, + "input": "0x61027a61003a600b82828239805160001a60731461002d57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600436106100355760003560e01c8063bb2960751461003a575b600080fd5b61004d610048366004610131565b61005f565b60405190815260200160405180910390f35b6000808361006f866127106101f8565b610079919061020f565b90506000620f424082856040015163ffffffff1661009791906101f8565b6100a1919061020f565b9050600081856000015161ffff166100b99190610231565b905060006100cf866020015161ffff16836100e7565b90506100db8188610101565b98975050505050505050565b60008183106100f657816100f8565b825b90505b92915050565b600061271061011084846101f8565b6100f8919061020f565b803561ffff8116811461012c57600080fd5b919050565b600080600083850360a081121561014757600080fd5b84359350602085013592506060603f198201121561016457600080fd5b506040516060810181811067ffffffffffffffff8211171561019657634e487b7160e01b600052604160045260246000fd5b80604052506101a76040860161011a565b81526101b56060860161011a565b6020820152608085013563ffffffff811681146101d157600080fd5b604082015292959194509192509050565b634e487b7160e01b600052601160045260246000fd5b80820281158282048414176100fb576100fb6101e2565b60008261022c57634e487b7160e01b600052601260045260246000fd5b500490565b808201808211156100fb576100fb6101e256fea26469706673582212208d1cbada5250b0f0ee7f487f17b8024885b2c4a3e362b79a95a6ab87356ad76864736f6c63430008170033", + "nonce": "0x141", + "chainId": "0xaa36a7", + "accessList": null, + "type": null + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0xc0328521eb096b2b664efd70f89a555d94c03a0ec48c29bcdd4b16b31a4d1135", + "transactionType": "CREATE", + "contractName": "NounsDAOFork", + "contractAddress": "0x3f08ce1a659c34737d1a1aae437bf5a99a1857be", + "function": null, + "arguments": null, + "transaction": { + "from": "0xad36c32f3c28a9214adcf50a09998de1d3b0ee06", + "to": null, + "gas": "0x15fc5d", + "value": null, + "input": "0x61131761003a600b82828239805160001a60731461002d57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600436106100925760003560e01c8063704a3b1211610065578063704a3b12146101125780637a868d3e14610152578063aeaa6be614610172578063f667e1141461019257600080fd5b80630577a8461461009757806313d419f6146100b957806319244b17146100df5780636055f935146100f2575b600080fd5b8180156100a357600080fd5b506100b76100b2366004610efe565b6101b2565b005b6100cc6100c7366004610f4a565b6102f8565b6040519081526020015b60405180910390f35b6100cc6100ed366004610f4a565b610379565b8180156100fe57600080fd5b506100b761010d366004610efe565b6103a0565b81801561011e57600080fd5b5061013261012d366004610f4a565b6103c2565b604080516001600160a01b039384168152929091166020830152016100d6565b81801561015e57600080fd5b506100b761016d366004610f63565b61063c565b81801561017e57600080fd5b506100b761018d36600461104c565b6107e1565b81801561019e57600080fd5b506100b76101ad366004610f63565b610866565b60158301544210156101d7576040516366c8a93b60e01b815260040160405180910390fd5b6010830154604051633567f93d60e11b8152600160601b9091046001600160a01b0316908190636acff27a90610215903390879087906004016110dd565b600060405180830381600087803b15801561022f57600080fd5b505af1158015610243573d6000803e3d6000fd5b50505050336001600160a01b0316816001600160a01b031663d7e53db06040518163ffffffff1660e01b8152600401602060405180830381865afa15801561028f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102b3919061110b565b63ffffffff167f7e066a27b070725cdb5ae51be8128dc95d65af0841137f77ec895c775f69849985856040516102ea929190611138565b60405180910390a350505050565b600081601001600c9054906101000a90046001600160a01b03166001600160a01b031663aa34213b6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561034f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103739190611154565b92915050565b6000612710826017015461038c84610aa1565b6103969190611183565b610373919061119a565b60098301546103bd908490849084906001600160a01b0316610c1d565b505050565b6000806103d28360150154421090565b156103f0576040516366c8a93b60e01b815260040160405180910390fd5b600083601001600c9054906101000a90046001600160a01b031690506000816001600160a01b031663aa34213b6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561044c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104709190611154565b905061047b85610379565b811161049a57604051630698c25760e11b815260040160405180910390fd5b60008560160154426104ac91906111bc565b601187015460405163fb14694360e01b8152600481018390526001600160a01b03868116602483015292935091169063fb1469439060440160408051808303816000875af1158015610502573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061052691906111cf565b909550935061053f86868461053a83610aa1565b610ce7565b6000836001600160a01b031663c163de3d6040518163ffffffff1660e01b81526004016020604051808303816000875af1158015610581573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105a5919061110b565b6013880180546001600160a01b038981166001600160a01b0319928316811790935560148b018054918a1691909216811790915560158a0185905560408051928352602083019190915281018490526060810185905290915063ffffffff8216907fb924f7ec9fa839e53ec987276a1a33b95a0aa0796ca86204f365925ac2dbded99060800160405180910390a250505050915091565b6015870154421015610661576040516366c8a93b60e01b815260040160405180910390fd5b6010870154600160601b90046001600160a01b031660005b8681101561072357600a8901546001600160a01b03166342842e0e33848b8b868181106106a8576106a8611209565b6040516001600160e01b031960e088901b1681526001600160a01b03958616600482015294909316602485015250602090910201356044820152606401600060405180830381600087803b1580156106ff57600080fd5b505af1158015610713573d6000803e3d6000fd5b5050600190920191506106799050565b50336001600160a01b0316816001600160a01b031663d7e53db06040518163ffffffff1660e01b8152600401602060405180830381865afa15801561076c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610790919061110b565b63ffffffff167f9a9bbe8a8a2c2b1e1d690cccd211b60ef1d2976f404800ed20604e57d3ed0f2d8989898989896040516107cf9695949392919061121f565b60405180910390a35050505050505050565b60098401546001600160a01b03908116908216036108125760405163c37a1e1760e01b815260040160405180910390fd5b61081e84848484610c1d565b604080518381526001600160a01b03831660208201527f855244575056ebffdfb115e332dfa96f1cd148bfe5bf486758fdd2d55b6fe9eb91015b60405180910390a150505050565b6015870154421061088a57604051635a7d97a760e11b815260040160405180910390fd5b6010870154600988015460138901546001600160a01b03600160601b909304831692918216916108c1918b91168961053a83610aa1565b60005b8781101561096e57600a8a01546001600160a01b03166323b872dd33848c8c868181106108f3576108f3611209565b6040516001600160e01b031960e088901b1681526001600160a01b03958616600482015294909316602485015250602090910201356044820152606401600060405180830381600087803b15801561094a57600080fd5b505af115801561095e573d6000803e3d6000fd5b5050600190920191506108c49050565b5060148901546040516374ea764760e01b81526001600160a01b03909116906374ea7647906109a59033908c908c906004016110dd565b600060405180830381600087803b1580156109bf57600080fd5b505af11580156109d3573d6000803e3d6000fd5b50505050336001600160a01b03166001836001600160a01b031663d7e53db06040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a21573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a45919061110b565b610a4f919061127e565b63ffffffff167f96ca5dab079aba8ed43c71a25c6090b5bce0e3f9ebcb4080816655b7a2d5a36f8a8a8a8a8a8a604051610a8e9695949392919061121f565b60405180910390a3505050505050505050565b600081601001600c9054906101000a90046001600160a01b03166001600160a01b0316639b3c1e226040518163ffffffff1660e01b8152600401602060405180830381865afa158015610af8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b1c9190611154565b600a83015460098401546040516370a0823160e01b81526001600160a01b0391821660048201529116906370a0823190602401602060405180830381865afa158015610b6c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b909190611154565b83600a0160009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610be5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c099190611154565b610c1391906112a2565b61037391906112a2565b83546001600160a01b03163314610c4757604051633057182d60e21b815260040160405180910390fd5b601084015460405163341f601360e21b8152600160601b9091046001600160a01b03169063d07d804c90610c83908690869086906004016112b5565b600060405180830381600087803b158015610c9d57600080fd5b505af1158015610cb1573d6000803e3d6000fd5b505050507e5508ab2be53c6629a9db1afe9702076dc2c4c4f344d60e711a315891d7141e838383604051610858939291906112b5565b60098401546001600160a01b0316600082610d03858431611183565b610d0d919061119a565b6040516364a197f360e01b81526001600160a01b03878116600483015260248201839052919250908316906364a197f390604401600060405180830381600087803b158015610d5b57600080fd5b505af1158015610d6f573d6000803e3d6000fd5b50505050601286015460005b81811015610ea8576000886012018281548110610d9a57610d9a611209565b60009182526020822001546040516370a0823160e01b81526001600160a01b03888116600483015290911692508790899084906370a0823190602401602060405180830381865afa158015610df3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e179190611154565b610e219190611183565b610e2b919061119a565b90508015610e9e576040516323e5d69960e21b81526001600160a01b038a81166004830152838116602483015260448201839052871690638f975a6490606401600060405180830381600087803b158015610e8557600080fd5b505af1158015610e99573d6000803e3d6000fd5b505050505b5050600101610d7b565b5050505050505050565b60008083601f840112610ec457600080fd5b50813567ffffffffffffffff811115610edc57600080fd5b6020830191508360208260051b8501011115610ef757600080fd5b9250929050565b600080600060408486031215610f1357600080fd5b83359250602084013567ffffffffffffffff811115610f3157600080fd5b610f3d86828701610eb2565b9497909650939450505050565b600060208284031215610f5c57600080fd5b5035919050565b60008060008060008060006080888a031215610f7e57600080fd5b87359650602088013567ffffffffffffffff80821115610f9d57600080fd5b610fa98b838c01610eb2565b909850965060408a0135915080821115610fc257600080fd5b610fce8b838c01610eb2565b909650945060608a0135915080821115610fe757600080fd5b818a0191508a601f830112610ffb57600080fd5b81358181111561100a57600080fd5b8b602082850101111561101c57600080fd5b60208301945080935050505092959891949750929550565b6001600160a01b038116811461104957600080fd5b50565b6000806000806060858703121561106257600080fd5b84359350602085013567ffffffffffffffff81111561108057600080fd5b61108c87828801610eb2565b90945092505060408501356110a081611034565b939692955090935050565b81835260006001600160fb1b038311156110c457600080fd5b8260051b80836020870137939093016020019392505050565b6001600160a01b038416815260406020820181905260009061110290830184866110ab565b95945050505050565b60006020828403121561111d57600080fd5b815163ffffffff8116811461113157600080fd5b9392505050565b60208152600061114c6020830184866110ab565b949350505050565b60006020828403121561116657600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b80820281158282048414176103735761037361116d565b6000826111b757634e487b7160e01b600052601260045260246000fd5b500490565b808201808211156103735761037361116d565b600080604083850312156111e257600080fd5b82516111ed81611034565b60208401519092506111fe81611034565b809150509250929050565b634e487b7160e01b600052603260045260246000fd5b60608152600061123360608301888a6110ab565b82810360208401526112468187896110ab565b90508281036040840152838152838560208301376000602085830101526020601f19601f860116820101915050979650505050505050565b63ffffffff82811682821603908082111561129b5761129b61116d565b5092915050565b818103818111156103735761037361116d565b6040815260006112c96040830185876110ab565b905060018060a01b038316602083015294935050505056fea2646970667358221220fd802a6052690f91ee05466d04b1d277dd3a3f33cdfc92bf23e0ec0373c36d9a64736f6c63430008170033", + "nonce": "0x142", + "chainId": "0xaa36a7", + "accessList": null, + "type": null + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0xacd69dc1124b78c0e1941053a221a43cd0c3751eada70aee92fa8cac7e79963b", + "transactionType": "CREATE", + "contractName": "NounsDAOProposals", + "contractAddress": "0x81ede38efc867818bf77978514f5dca76c20a050", + "function": null, + "arguments": null, + "transaction": { + "from": "0xad36c32f3c28a9214adcf50a09998de1d3b0ee06", + "to": null, + "gas": "0x4ffaae", + "value": null, + "input": "0x6147f961003a600b82828239805160001a60731461002d57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600436106101155760003560e01c806383478b43116100ac578063b0a3fc381161007b578063b0a3fc38146102ac578063b2faf4d4146102cc578063b7aa3e57146102ec578063ddb639831461030c578063f9df1e191461032c57600080fd5b806383478b431461021e578063853b94a01461023e57806392be51d814610265578063ac982f381461028557600080fd5b80633ce52dbe116100e85780633ce52dbe1461019e5780635e6ab1ac146101be57806373d0ed2f146101de5780637b55bff3146101fe57600080fd5b806320606b701461011a57806320660f531461015457806336e7048a14610174578063370d35771461017c575b600080fd5b6101417f8cad95687ba82c2ce50e74f7b754645e5117c3a5bec8151c0726d5857980a86681565b6040519081526020015b60405180910390f35b81801561016057600080fd5b5061014161016f3660046138a0565b61034c565b610141600a81565b81801561018857600080fd5b5061019c61019736600461394f565b6104bc565b005b8180156101aa57600080fd5b5061019c6101b936600461394f565b6104ea565b8180156101ca57600080fd5b5061019c6101d936600461394f565b6109b1565b6101f16101ec36600461394f565b610cd5565b60405161014b9190613987565b81801561020a57600080fd5b5061019c6102193660046139af565b610cea565b81801561022a57600080fd5b5061019c610239366004613ab8565b610d4e565b6101417fd4eafb6bc770edecb5da52765bc3f50af948bfe1b8344cf115f8ee7fefe55ec781565b61027861027336600461394f565b610daf565b60405161014b9190613b9c565b6101417fe5a9e6d2702042f3612beac0f605312204baddec2d19d1338da7e37e6c67d6ee81565b8180156102b857600080fd5b5061019c6102c7366004613ca3565b610f2c565b8180156102d857600080fd5b5061019c6102e736600461394f565b610f87565b8180156102f857600080fd5b5061019c610307366004613d25565b61118f565b61031f61031a36600461394f565b611211565b60405161014b9190613db5565b81801561033857600080fd5b5061019c610347366004613ee4565b61144f565b6000845160000361037057604051637a4783fb60e01b815260040160405180910390fd5b61037984611738565b6103a36040518060600160405280600063ffffffff16815260200160008152602001600081525090565b60088701546103b3906001613fb8565b600888018190556103c3906117cf565b63ffffffff1681526103d487611838565b602082018190526103e69088906119b4565b6040820181905281516020830151600092610407928b929091908a896119c4565b90506000806104238a8a8a8a886000015163ffffffff16611b8d565b91509150805160000361044957604051637a4783fb60e01b815260040160405180910390fd5b8360400151821161046d5760405163ead8241560e01b815260040160405180910390fd5b805161048290601285019060208401906132b4565b506104a7838261049f87602001518e611e5290919063ffffffff16565b8b8b8b611e6c565b5050905163ffffffff16979650505050505050565b6000818152600b830160205260408120906104d78483611f46565b90506104e4848383611f7e565b50505050565b60006104f683836121b2565b9050600281600a81111561050c5761050c613971565b14806105295750600381600a81111561052757610527613971565b145b806105455750600681600a81111561054357610543613971565b145b806105615750600781600a81111561055f5761055f613971565b145b8061057d5750600881600a81111561057b5761057b613971565b145b1561059b57604051635598baf360e01b815260040160405180910390fd5b6000828152600b840160205260408120600180820154600a87015492936001600160a01b039182169390911691829063782d6fe19085906105dc9043613fcb565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401602060405180830381865afa158015610625573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106499190613fde565b6001600160601b031690506000336001600160a01b0316846001600160a01b03161490506000856012018054806020026020016040519081016040528092919081815260200182805480156106c757602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116106a9575b5050505050905060005b81518110156107d257828061071057508181815181106106f3576106f361400e565b60200260200101516001600160a01b0316336001600160a01b0316145b9250846001600160a01b031663782d6fe18383815181106107335761073361400e565b60200260200101516001436107489190613fcb565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401602060405180830381865afa158015610791573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107b59190613fde565b6107c8906001600160601b031685613fb8565b93506001016106d1565b5081806107e3575085600201548311155b6108475760405162461bcd60e51b815260206004820152602a60248201527f4e6f756e7344414f3a3a63616e63656c3a2070726f706f7365722061626f7665604482015269081d1a1c995cda1bdb1960b21b60648201526084015b60405180910390fd5b600e8601805460ff1916600117905560006108628a88611f46565b905060005b600588015481101561097157816001600160a01b031663591fcdfe8960050183815481106108975761089761400e565b60009182526020909120015460068b0180546001600160a01b0390921691859081106108c5576108c561400e565b90600052602060002001548b60070185815481106108e5576108e561400e565b906000526020600020018c60080186815481106109045761090461400e565b906000526020600020018d600401546040518663ffffffff1660e01b81526004016109339594939291906140db565b600060405180830381600087803b15801561094d57600080fd5b505af1158015610961573d6000803e3d6000fd5b5050600190920191506108679050565b506040518981527f789cf55be980739dad1d0699b93b58e806b51c9d96619bfa8fe0a28abaa7b30c9060200160405180910390a150505050505050505050565b60046109bd83836121b2565b600a8111156109ce576109ce613971565b14610a415760405162461bcd60e51b815260206004820152603f60248201527f4e6f756e7344414f3a3a71756575653a2070726f706f73616c2063616e206f6e60448201527f6c79206265207175657565642069662069742069732073756363656564656400606482015260840161083e565b6000818152600b83016020526040812090610a5c8483611f46565b90506000816001600160a01b0316636a42b8f86040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a9e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ac29190614127565b610acc9042613fb8565b905060005b6005840154811015610c8d57610c8583856005018381548110610af657610af661400e565b6000918252602090912001546006870180546001600160a01b039092169185908110610b2457610b2461400e565b9060005260206000200154876007018581548110610b4457610b4461400e565b906000526020600020018054610b5990614024565b80601f0160208091040260200160405190810160405280929190818152602001828054610b8590614024565b8015610bd25780601f10610ba757610100808354040283529160200191610bd2565b820191906000526020600020905b815481529060010190602001808311610bb557829003601f168201915b5050505050886008018681548110610bec57610bec61400e565b906000526020600020018054610c0190614024565b80601f0160208091040260200160405190810160405280929190818152602001828054610c2d90614024565b8015610c7a5780601f10610c4f57610100808354040283529160200191610c7a565b820191906000526020600020905b815481529060010190602001808311610c5d57829003601f168201915b5050505050876123ab565b600101610ad1565b506004830181905560408051858152602081018390527f9a2e42fd6722813d69113e7d0079d3d940171428df7373df9c7f7617cfda2892910160405180910390a15050505050565b6000610ce183836121b2565b90505b92915050565b610cf8888888888888612554565b336001600160a01b0316877fd92cc1350c3c114b08bfa9ca07e42b8d07adf3c440ac299943edfbfb9be890ac888888888888604051610d3c9695949392919061421b565b60405180910390a35050505050505050565b610d5c878787878787612554565b336001600160a01b0316867f2588d794bdaac5e181a3efca6937bf6bac4e2f42f43dcfcf0492b3d8b54be0658787878787604051610d9e95949392919061429d565b60405180910390a350505050505050565b610e37604051806101e001604052806000815260200160006001600160a01b03168152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160001515815260200160001515815260200160001515815260200160008152602001600081525090565b6000828152600b8401602090815260409182902082516101e081018452815463ffffffff90811680835260018401546001600160a01b031694830194909452600283015494820194909452909290916060830191610e979188916125f916565b81526004830154602082015260098301546040820152600a8301546060820152600b8301546080820152600c83015460a0820152600d83015460c0820152600e83015460ff808216151560e0840152610100808304821615159084015262010000909104161515610120820152601083015461014082015260119092015463ffffffff16610160909201919091529392505050565b6000858152600b870160205260409020610f47878783612652565b336001600160a01b0316867fb326c35bcac6caacafa6cd1190bb9dc1a4e0aad7a7985e193818797dfbec990587878787604051610d9e9493929190614327565b60038201546001600160a01b0316610fb257604051631efc808d60e31b815260040160405180910390fd5b60038201546001600160a01b03163314610fdf57604051631387214760e01b815260040160405180910390fd5b6007610feb83836121b2565b600a811115610ffc57610ffc613971565b0361101a57604051636c0a12d560e01b815260040160405180910390fd5b6000818152600b830160205260408120600e8101805461ff001916610100179055906110468483611f46565b905060005b600583015481101561115557816001600160a01b031663591fcdfe84600501838154811061107b5761107b61400e565b6000918252602090912001546006860180546001600160a01b0390921691859081106110a9576110a961400e565b90600052602060002001548660070185815481106110c9576110c961400e565b906000526020600020018760080186815481106110e8576110e861400e565b9060005260206000200188600401546040518663ffffffff1660e01b81526004016111179594939291906140db565b600060405180830381600087803b15801561113157600080fd5b505af1158015611145573d6000803e3d6000fd5b50506001909201915061104b9050565b506040518381527fde0cea2a3a0097cc3d981d40c375407760e85bc9c5e69aea449ac3885f8615c69060200160405180910390a150505050565b600082826040516111a192919061434e565b60408051918290038220336000818152600f89016020908152848220848352905292909220805460ff191660011790559250907f45f194850d9c26cfb50dad5456a1c64997b6a4d461d0159f372282ba183d854d90611203908690869061435e565b60405180910390a250505050565b6112b76040518061026001604052806000815260200160006001600160a01b03168152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160001515815260200160001515815260200160001515815260200160008152602001600081526020016060815260200160008152602001600081526020016000151581525090565b6000828152600b84016020908152604091829020825161026081018452815463ffffffff90811680835260018401546001600160a01b0316948301949094526002830154948201949094529092909160608301916113179188916125f916565b815260048301546020808301919091526009840154604080840191909152600a8501546060840152600b8501546080840152600c85015460a0840152600d85015460c0840152600e85015460ff808216151560e08601526101008083048216151590860152620100009091041615156101208401526010850154610140840152601185015463ffffffff1661016084015260128501805482518185028101850190935280835261018090940193919290919083018282801561140257602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116113e4575b505050918352505060118301546001600160401b03600160401b820481166020840152600160801b90910416604082015260139092015460ff161515606090920191909152905092915050565b61145883611738565b835160000361147a57604051637a4783fb60e01b815260040160405180910390fd5b6000858152600b870160205260409020600a61149688886121b2565b600a8111156114a7576114a7613971565b146114c5576040516339abb30760e21b815260040160405180910390fd5b60018101546001600160a01b031633146114f257604051631d6b368d60e01b815260040160405180910390fd5b60008160120180548060200260200160405190810160405280929190818152602001828054801561154c57602002820191906000526020600020905b81546001600160a01b0316815260019091019060200180831161152e575b5050505050905080518651146115755760405163b92ba76160e01b815260040160405180910390fd5b6000876115833388886126e2565b604051602001611594929190614372565b604051602081830303815290604052905060005b8751811015611666576115f68a838a84815181106115c8576115c861400e565b60200260200101517fe5a9e6d2702042f3612beac0f605312204baddec2d19d1338da7e37e6c67d6ee61292d565b8781815181106116085761160861400e565b6020026020010151602001516001600160a01b031683828151811061162f5761162f61400e565b60200260200101516001600160a01b03161461165e57604051631d6b368d60e01b815260040160405180910390fd5b6001016115a8565b508551805161167f9160058601916020909101906132b4565b5060208087015180516116989260068701920190613315565b50604086015180516116b4916007860191602090910190613350565b50606086015180516116d09160088601916020909101906133a2565b50336001600160a01b0316887fd92cc1350c3c114b08bfa9ca07e42b8d07adf3c440ac299943edfbfb9be890ac886000015189602001518a604001518b606001518b8b6040516117259695949392919061421b565b60405180910390a3505050505050505050565b602081015151815151141580611755575060408101515181515114155b80611767575060608101515181515114155b156117855760405163ccb0ce3f60e01b815260040160405180910390fd5b8051516000036117a857604051630f24cd7360e01b815260040160405180910390fd5b805151600a10156117cc576040516308e3b1eb60e11b815260040160405180910390fd5b50565b600063ffffffff8211156118345760405162461bcd60e51b815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203360448201526532206269747360d01b606482015260840161083e565b5090565b600081601001600c9054906101000a90046001600160a01b03166001600160a01b0316639b3c1e226040518163ffffffff1660e01b8152600401602060405180830381865afa15801561188f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118b39190614127565b600a83015460098401546040516370a0823160e01b81526001600160a01b0391821660048201529116906370a0823190602401602060405180830381865afa158015611903573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119279190614127565b83600a0160009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561197c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119a09190614127565b6119aa9190613fcb565b610ce49190613fcb565b6000610ce18360060154836129f1565b601086015460009081906119ee906119e990600160401b900463ffffffff1643613fb8565b612a0a565b905060008860040154826001600160401b0316611a0b9190613fb8565b90506000896005015482611a1f9190613fb8565b63ffffffff808b166000818152600b8e01602090815260409091208054938a166401000000000267ffffffffffffffff199094169092179290921781556001810180546001600160a01b03191633179055600281018b905588518051919750929350611a9192600588019201906132b4565b506020808701518051611aaa9260068801920190613315565b5060408601518051611ac6916007870191602090910190613350565b5060608601518051611ae29160088701916020909101906133a2565b5060098401829055600a840181905560108401879055611b01436117cf565b60118501805463ffffffff191663ffffffff92909216919091179055611b26426117cf565b6011850180546001600160401b03909516600160401b026fffffffffffffffff00000000000000001963ffffffff9390931664010000000002929092166fffffffffffffffffffffffff000000001990951694909417179092555090979650505050505050565b600a8501546000906060906001600160a01b031682611bad3388886126e2565b905087516001600160401b03811115611bc857611bc861347d565b604051908082528060200260200182016040528015611bf1578160200160208202803683370190505b5092506000805b8951811015611d7b57611c468b848c8481518110611c1857611c1861400e565b60200260200101517fd4eafb6bc770edecb5da52765bc3f50af948bfe1b8344cf115f8ee7fefe55ec761292d565b60008a8281518110611c5a57611c5a61400e565b6020026020010151602001519050611c728c82612a72565b60006001600160a01b03861663782d6fe183611c8f600143613fcb565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401602060405180830381865afa158015611cd8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cfc9190613fde565b6001600160601b0316905080600003611d16575050611d73565b818785611d2281614398565b965081518110611d3457611d3461400e565b6001600160a01b039283166020918202929092018101919091529083166000908152600c8f0190915260409020899055611d6e8189613fb8565b975050505b600101611bf8565b508851811015611d89578084525b611d938a33612a72565b336000818152600c8c01602052604090208790556001600160a01b0384169063782d6fe190611dc3600143613fcb565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401602060405180830381865afa158015611e0c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e309190613fde565b611e43906001600160601b031686613fb8565b94505050509550959350505050565b6000610ce1611e618443612b28565b5161ffff16836129f1565b855483516020850151604080870151606088015160098c0154600a8d015493517f7d84a6263ae0d98d3329bd7b46bb4e8d6f98cd35a7adb45c274c8b7fd5ebd5e097611ecf9763ffffffff90911696339691959094909390929091908c906143b1565b60405180910390a185546011870154600288015460405163ffffffff808616947fd9d12651716feaac10e3b79bd2960ad42ebfd84969b71a2e226ec99972a8712e94611f369491909216928b926001600160401b03600160401b9091041691908b9061444f565b60405180910390a2505050505050565b601381015460009060ff1615611f6a575060188201546001600160a01b0316610ce4565b5060098201546001600160a01b0316610ce4565b60058254611f9390859063ffffffff166121b2565b600a811115611fa457611fa4613971565b14612019576040805162461bcd60e51b81526020600482015260248101919091527f4e6f756e7344414f3a3a657865637574653a2070726f706f73616c2063616e2060448201527f6f6e6c7920626520657865637574656420696620697420697320717565756564606482015260840161083e565b601583015442101561203e57604051633183594360e21b815260040160405180910390fd5b600e8201805462ff000019166201000017905560005b600583015481101561217057816001600160a01b0316630825f38f8460050183815481106120845761208461400e565b6000918252602090912001546006860180546001600160a01b0390921691859081106120b2576120b261400e565b90600052602060002001548660070185815481106120d2576120d261400e565b906000526020600020018760080186815481106120f1576120f161400e565b9060005260206000200188600401546040518663ffffffff1660e01b81526004016121209594939291906140db565b6000604051808303816000875af115801561213f573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526121679190810190614494565b50600101612054565b50815460405163ffffffff90911681527f712ae1383f79ac853f8d882153778e0260ef8f03b504e2866e0593e04d2b291f9060200160405180910390a1505050565b600081836008015410156122145760405162461bcd60e51b8152602060048201526024808201527f4e6f756e7344414f3a3a73746174653a20696e76616c69642070726f706f73616044820152631b081a5960e21b606482015260840161083e565b6000828152600b840160205260409020600e810154610100900460ff1615612240576008915050610ce4565b600e81015460ff1615612257576002915050610ce4565b6011810154600160401b90046001600160401b0316431161227c57600a915050610ce4565b80600901544311612291576000915050610ce4565b80600a015443116122a6576001915050610ce4565b6011810154600160801b90046001600160401b031643116122cb576009915050610ce4565b6122d58482612e3d565b156122e4576003915050610ce4565b80600401546000036122fa576004915050610ce4565b600e81015462010000900460ff1615612317576007915050610ce4565b6123218482611f46565b6001600160a01b031663c1a287e26040518163ffffffff1660e01b8152600401602060405180830381865afa15801561235e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123829190614127565b81600401546123919190613fb8565b42106123a1576006915050610ce4565b6005915050610ce4565b856001600160a01b031663f2b0653786868686866040516020016123d395949392919061450a565b604051602081830303815290604052805190602001206040518263ffffffff1660e01b815260040161240791815260200190565b602060405180830381865afa158015612424573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124489190614543565b156124d45760405162461bcd60e51b815260206004820152605060248201527f4e6f756e7344414f3a3a71756575654f72526576657274496e7465726e616c3a60448201527f206964656e746963616c2070726f706f73616c20616374696f6e20616c72656160648201526f6479207175657565642061742065746160801b608482015260a40161083e565b604051633a66f90160e01b81526001600160a01b03871690633a66f90190612508908890889088908890889060040161450a565b6020604051808303816000875af1158015612527573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061254b9190614127565b50505050505050565b61257d604051806080016040528086815260200185815260200184815260200183815250611738565b6000858152600b870160205260409020612598878783612652565b84516125ad90600583019060208801906132b4565b5083516125c39060068301906020870190613315565b5082516125d99060078301906020860190613350565b5081516125ef90600883019060208501906133a2565b5050505050505050565b6000818152600b8301602052604081206010810154820361261f57600301549050610ce4565b600c8101546010820154601183015461264a92919061264590889063ffffffff16612b28565b612e73565b949350505050565b600a61265e84846121b2565b600a81111561266f5761266f613971565b1461268d576040516339abb30760e21b815260040160405180910390fd5b60018101546001600160a01b031633146126ba57604051631d6b368d60e01b815260040160405180910390fd5b6012810154156126dd57604051630e13f93360e11b815260040160405180910390fd5b505050565b606060008360400151516001600160401b038111156127035761270361347d565b60405190808252806020026020018201604052801561272c578160200160208202803683370190505b50905060005b84604001515181101561278957846040015181815181106127555761275561400e565b6020026020010151805190602001208282815181106127765761277661400e565b6020908102919091010152600101612732565b5060008460600151516001600160401b038111156127a9576127a961347d565b6040519080825280602002602001820160405280156127d2578160200160208202803683370190505b50905060005b85606001515181101561282f57856060015181815181106127fb576127fb61400e565b60200260200101518051906020012082828151811061281c5761281c61400e565b60209081029190910101526001016127d8565b508451604051879161284391602001614565565b60405160208183030381529060405280519060200120866020015160405160200161286e91906145a4565b604051602081830303815290604052805190602001208460405160200161289591906145a4565b60405160208183030381529060405280519060200120846040516020016128bc91906145a4565b60408051601f1981840301815282825280516020918201208b518c8301206001600160a01b0390981691840191909152908201949094526060810192909252608082015260a081019190915260c081019190915260e001604051602081830303815290604052925050509392505050565b81518051602091820120818401516001600160a01b03166000908152600f870183526040808220838352909352919091205460ff161561298057604051634260f73960e01b815260040160405180910390fd5b60006129928386866040015130612efb565b90506129a78460200151828660000151612ff3565b6129c457604051638baa579f60e01b815260040160405180910390fd5b83604001514211156129e957604051630819bdcd60e01b815260040160405180910390fd5b505050505050565b6000612710612a0084846145ce565b610ce191906145e5565b60006001600160401b038211156118345760405162461bcd60e51b815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203660448201526534206269747360d01b606482015260840161083e565b6001600160a01b0381166000908152600c8301602052604090205480156126dd576000612a9f84836121b2565b9050600981600a811115612ab557612ab5613971565b1480612ad25750600181600a811115612ad057612ad0613971565b145b80612aee5750600081600a811115612aec57612aec613971565b145b80612b0a5750600a81600a811115612b0857612b08613971565b145b156104e4576040516306bee79560e01b815260040160405180910390fd5b60408051606081018252600080825260208201819052918101919091526000612b698360405180606001604052806040815260200161478460409139613054565b600d8501549091506000819003612bc0576040518060600160405280612b928760070154613084565b61ffff168152602001612ba88760070154613084565b61ffff16815260006020909101529250610ce4915050565b63ffffffff8216600d8601612bd6600184613fcb565b81548110612be657612be661400e565b600091825260209091206002909102015463ffffffff1611612c7957600d8501612c11600183613fcb565b81548110612c2157612c2161400e565b6000918252602091829020604080516060810182526002939093029091016001015461ffff8082168452620100008204169383019390935264010000000090920463ffffffff16918101919091529250610ce4915050565b8163ffffffff1685600d01600081548110612c9657612c9661400e565b600091825260209091206002909102015463ffffffff161115612ccb576040518060600160405280612b928760070154613084565b600080612cd9600184613fcb565b90505b81811115612dcf5760006002612cf28484613fcb565b612cfc91906145e5565b612d069083613fcb565b9050600088600d018281548110612d1f57612d1f61400e565b60009182526020918290206040805180820182526002909302909101805463ffffffff9081168452825160608101845260019092015461ffff808216845262010000820416838701526401000000009004811692820192909252928201929092528051909250878216911603612da057602001519550610ce4945050505050565b805163ffffffff80881691161015612dba57819350612dc8565b612dc5600183613fcb565b92505b5050612cdc565b86600d018281548110612de457612de461400e565b6000918252602091829020604080516060810182526002939093029091016001015461ffff8082168452620100008204169383019390935264010000000090920463ffffffff1691810191909152979650505050505050565b600b810154600c820154600091908111158061264a57508254612e6b90859063ffffffff908116906125f916565b119392505050565b60008083612e83866127106145ce565b612e8d91906145e5565b90506000620f424082856040015163ffffffff16612eab91906145ce565b612eb591906145e5565b9050600081856000015161ffff16612ecd9190613fb8565b90506000612ee3866020015161ffff16836130a9565b9050612eef81886129f1565b98975050505050505050565b600080858585604051602001612f1393929190614607565b60408051601f198184030181528282528051602091820120838301835260098452684e6f756e732044414f60b81b9382019390935281517f8cad95687ba82c2ce50e74f7b754645e5117c3a5bec8151c0726d5857980a866818301527fe1dd93b3612547b4bb7c3d429f3df8508d84f5a4f63b5e2e44340b94698e6b3b818401524660608201526001600160a01b0387166080808301919091528351808303909101815260a0820193849052805192019190912061190160f01b835260a2820181905260c29091018390526042909120919250905b979650505050505050565b600080600061300285856130bf565b9092509050600081600481111561301b5761301b613971565b1480156130395750856001600160a01b0316826001600160a01b0316145b8061304a575061304a868686613104565b9695505050505050565b60008163ffffffff84111561307c5760405162461bcd60e51b815260040161083e9190614634565b509192915050565b600061ffff8211156118345760405163555abf0160e11b815260040160405180910390fd5b60008183106130b85781610ce1565b5090919050565b60008082516041036130f55760208301516040840151606085015160001a6130e9878285856131f0565b945094505050506130fd565b506000905060025b9250929050565b6000806000856001600160a01b0316631626ba7e60e01b868660405160240161312e929190614647565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b031990941693909317909252905161316c9190614660565b600060405180830381855afa9150503d80600081146131a7576040519150601f19603f3d011682016040523d82523d6000602084013e6131ac565b606091505b50915091508180156131c057506020815110155b801561304a57508051630b135d3f60e11b906131e59083016020908101908401614127565b149695505050505050565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a083111561322757506000905060036132ab565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa15801561327b573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b0381166132a4576000600192509250506132ab565b9150600090505b94509492505050565b828054828255906000526020600020908101928215613309579160200282015b8281111561330957825182546001600160a01b0319166001600160a01b039091161782556020909201916001909101906132d4565b506118349291506133f4565b828054828255906000526020600020908101928215613309579160200282015b82811115613309578251825591602001919060010190613335565b828054828255906000526020600020908101928215613396579160200282015b82811115613396578251829061338690826146c4565b5091602001919060010190613370565b50611834929150613409565b8280548282559060005260206000209081019282156133e8579160200282015b828111156133e857825182906133d890826146c4565b50916020019190600101906133c2565b50611834929150613426565b5b8082111561183457600081556001016133f5565b8082111561183457600061341d8282613443565b50600101613409565b8082111561183457600061343a8282613443565b50600101613426565b50805461344f90614024565b6000825580601f1061345f575050565b601f0160209004906000526020600020908101906117cc91906133f4565b634e487b7160e01b600052604160045260246000fd5b604051606081016001600160401b03811182821017156134b5576134b561347d565b60405290565b604051608081016001600160401b03811182821017156134b5576134b561347d565b604051601f8201601f191681016001600160401b03811182821017156135055761350561347d565b604052919050565b60006001600160401b038211156135265761352661347d565b5060051b60200190565b60006001600160401b038211156135495761354961347d565b50601f01601f191660200190565b600082601f83011261356857600080fd5b813561357b61357682613530565b6134dd565b81815284602083860101111561359057600080fd5b816020850160208301376000918101602001919091529392505050565b80356001600160a01b03811681146135c457600080fd5b919050565b600082601f8301126135da57600080fd5b813560206135ea6135768361350d565b82815260059290921b8401810191818101908684111561360957600080fd5b8286015b848110156136995780356001600160401b038082111561362d5760008081fd5b908801906060828b03601f19018113156136475760008081fd5b61364f613493565b87840135838111156136615760008081fd5b61366f8d8a83880101613557565b825250604092506136818385016135ad565b8189015292013590820152835291830191830161360d565b509695505050505050565b600082601f8301126136b557600080fd5b813560206136c56135768361350d565b8083825260208201915060208460051b8701019350868411156136e757600080fd5b602086015b84811015613699576136fd816135ad565b83529183019183016136ec565b600082601f83011261371b57600080fd5b8135602061372b6135768361350d565b8083825260208201915060208460051b87010193508684111561374d57600080fd5b602086015b848110156136995780358352918301918301613752565b600082601f83011261377a57600080fd5b8135602061378a6135768361350d565b82815260059290921b840181019181810190868411156137a957600080fd5b8286015b848110156136995780356001600160401b038111156137cc5760008081fd5b6137da8986838b0101613557565b8452509183019183016137ad565b6000608082840312156137fa57600080fd5b6138026134bb565b905081356001600160401b038082111561381b57600080fd5b613827858386016136a4565b8352602084013591508082111561383d57600080fd5b6138498583860161370a565b6020840152604084013591508082111561386257600080fd5b61386e85838601613769565b6040840152606084013591508082111561388757600080fd5b5061389484828501613769565b60608301525092915050565b600080600080600060a086880312156138b857600080fd5b8535945060208601356001600160401b03808211156138d657600080fd5b6138e289838a016135c9565b955060408801359150808211156138f857600080fd5b61390489838a016137e8565b9450606088013591508082111561391a57600080fd5b5061392788828901613557565b925050608086013563ffffffff8116811461394157600080fd5b809150509295509295909350565b6000806040838503121561396257600080fd5b50508035926020909101359150565b634e487b7160e01b600052602160045260246000fd5b60208101600b83106139a957634e487b7160e01b600052602160045260246000fd5b91905290565b600080600080600080600080610100898b0312156139cc57600080fd5b883597506020890135965060408901356001600160401b03808211156139f157600080fd5b6139fd8c838d016136a4565b975060608b0135915080821115613a1357600080fd5b613a1f8c838d0161370a565b965060808b0135915080821115613a3557600080fd5b613a418c838d01613769565b955060a08b0135915080821115613a5757600080fd5b613a638c838d01613769565b945060c08b0135915080821115613a7957600080fd5b613a858c838d01613557565b935060e08b0135915080821115613a9b57600080fd5b50613aa88b828c01613557565b9150509295985092959890939650565b600080600080600080600060e0888a031215613ad357600080fd5b873596506020880135955060408801356001600160401b0380821115613af857600080fd5b613b048b838c016136a4565b965060608a0135915080821115613b1a57600080fd5b613b268b838c0161370a565b955060808a0135915080821115613b3c57600080fd5b613b488b838c01613769565b945060a08a0135915080821115613b5e57600080fd5b613b6a8b838c01613769565b935060c08a0135915080821115613b8057600080fd5b50613b8d8a828b01613557565b91505092959891949750929550565b815181526020808301516101e0830191613bc0908401826001600160a01b03169052565b5060408301516040830152606083015160608301526080830151608083015260a083015160a083015260c083015160c083015260e083015160e083015261010080840151818401525061012080840151818401525061014080840151613c298285018215159052565b505061016083810151151590830152610180808401511515908301526101a080840151908301526101c092830151929091019190915290565b60008083601f840112613c7457600080fd5b5081356001600160401b03811115613c8b57600080fd5b6020830191508360208285010111156130fd57600080fd5b60008060008060008060808789031215613cbc57600080fd5b863595506020870135945060408701356001600160401b0380821115613ce157600080fd5b613ced8a838b01613c62565b90965094506060890135915080821115613d0657600080fd5b50613d1389828a01613c62565b979a9699509497509295939492505050565b600080600060408486031215613d3a57600080fd5b8335925060208401356001600160401b03811115613d5757600080fd5b613d6386828701613c62565b9497909650939450505050565b60008151808452602080850194506020840160005b83811015613daa5781516001600160a01b031687529582019590820190600101613d85565b509495945050505050565b602081528151602082015260006020830151613ddc60408401826001600160a01b03169052565b506040830151606083015260608301516080830152608083015160a083015260a083015160c083015260c083015160e083015260e0830151610100818185015280850151915050610120818185015280850151915050610140818185015280850151915050610160613e518185018315159052565b8401519050610180613e668482018315159052565b84015190506101a0613e7b8482018315159052565b8401516101c0848101919091528401516101e08085019190915284015161026061020080860182905291925090613eb6610280860184613d70565b9086015161022086810191909152860151610240808701919091529095015115159301929092525090919050565b60008060008060008060c08789031215613efd57600080fd5b863595506020870135945060408701356001600160401b0380821115613f2257600080fd5b613f2e8a838b016135c9565b95506060890135915080821115613f4457600080fd5b613f508a838b016137e8565b94506080890135915080821115613f6657600080fd5b613f728a838b01613557565b935060a0890135915080821115613f8857600080fd5b50613f9589828a01613557565b9150509295509295509295565b634e487b7160e01b600052601160045260246000fd5b80820180821115610ce457610ce4613fa2565b81810381811115610ce457610ce4613fa2565b600060208284031215613ff057600080fd5b81516001600160601b038116811461400757600080fd5b9392505050565b634e487b7160e01b600052603260045260246000fd5b600181811c9082168061403857607f821691505b60208210810361405857634e487b7160e01b600052602260045260246000fd5b50919050565b6000815461406b81614024565b80855260206001838116801561408857600181146140a2576140d0565b60ff1985168884015283151560051b8801830195506140d0565b866000528260002060005b858110156140c85781548a82018601529083019084016140ad565b890184019650505b505050505092915050565b60018060a01b038616815284602082015260a06040820152600061410260a083018661405e565b8281036060840152614114818661405e565b9150508260808301529695505050505050565b60006020828403121561413957600080fd5b5051919050565b60008151808452602080850194506020840160005b83811015613daa57815187529582019590820190600101614155565b60005b8381101561418c578181015183820152602001614174565b50506000910152565b600081518084526141ad816020860160208601614171565b601f01601f19169290920160200192915050565b60008282518085526020808601955060208260051b8401016020860160005b8481101561420e57601f198684030189526141fc838351614195565b988401989250908301906001016141e0565b5090979650505050505050565b60c08152600061422e60c0830189613d70565b82810360208401526142408189614140565b9050828103604084015261425481886141c1565b9050828103606084015261426881876141c1565b9050828103608084015261427c8186614195565b905082810360a08401526142908185614195565b9998505050505050505050565b60a0815260006142b060a0830188613d70565b82810360208401526142c28188614140565b905082810360408401526142d681876141c1565b905082810360608401526142ea81866141c1565b90508281036080840152612eef8185614195565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b60408152600061433b6040830186886142fe565b8281036020840152612fe88185876142fe565b8183823760009101908152919050565b60208152600061264a6020830184866142fe565b8281526000825161438a816020850160208701614171565b919091016020019392505050565b6000600182016143aa576143aa613fa2565b5060010190565b63ffffffff8a1681526001600160a01b0389166020820152610120604082018190526000906143e28382018b613d70565b905082810360608401526143f6818a614140565b9050828103608084015261440a81896141c1565b905082810360a084015261441e81886141c1565b90508560c08401528460e084015282810361010084015261443f8185614195565b9c9b505050505050505050505050565b63ffffffff8616815260a06020820152600061446e60a0830187613d70565b6001600160401b0395909516604083015250606081019290925260809091015292915050565b6000602082840312156144a657600080fd5b81516001600160401b038111156144bc57600080fd5b8201601f810184136144cd57600080fd5b80516144db61357682613530565b8181528560208385010111156144f057600080fd5b614501826020830160208601614171565b95945050505050565b60018060a01b038616815284602082015260a06040820152600061453160a0830186614195565b82810360608401526141148186614195565b60006020828403121561455557600080fd5b8151801515811461400757600080fd5b815160009082906020808601845b838110156145985781516001600160a01b031685529382019390820190600101614573565b50929695505050505050565b815160009082906020808601845b83811015614598578151855293820193908201906001016145b2565b8082028115828204841417610ce457610ce4613fa2565b60008261460257634e487b7160e01b600052601260045260246000fd5b500490565b8381526000835161461f816020850160208801614171565b60209201918201929092526040019392505050565b602081526000610ce16020830184614195565b82815260406020820152600061264a6040830184614195565b60008251614672818460208701614171565b9190910192915050565b601f8211156126dd576000816000526020600020601f850160051c810160208610156146a55750805b601f850160051c820191505b818110156129e9578281556001016146b1565b81516001600160401b038111156146dd576146dd61347d565b6146f1816146eb8454614024565b8461467c565b602080601f831160018114614726576000841561470e5750858301515b600019600386901b1c1916600185901b1785556129e9565b600085815260208120601f198616915b8281101561475557888601518255948401946001909101908401614736565b50858210156147735787850151600019600388901b60f8161c191681555b5050505050600190811b0190555056fe4e6f756e7344414f3a3a67657444796e616d696351756f72756d506172616d7341743a20626c6f636b206e756d62657220657863656564732033322062697473a26469706673582212203d27194f160b95bf2f25018dac840393c3bd014f71918b4913b59d1cbc642ae964736f6c63430008170033", + "nonce": "0x143", + "chainId": "0xaa36a7", + "accessList": null, + "type": null + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0xd8e5ad5005fa8e231687ee17d418d98e0bf39f486d83f80aec0d71fdff72999a", + "transactionType": "CREATE", + "contractName": "NounsDAOVotes", + "contractAddress": "0x30656985039923eaa1ebb968fe84a1277581f602", + "function": null, + "arguments": null, + "transaction": { + "from": "0xad36c32f3c28a9214adcf50a09998de1d3b0ee06", + "to": null, + "gas": "0x1dc81a", + "value": null, + "input": "0x611a3361003a600b82828239805160001a60731461002d57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600436106100be5760003560e01c8063b73a99c71161007b578063b73a99c714610187578063bc4cd084146101a7578063deaaa7cc146101b3578063e105d84a146101da578063f57e66d1146101fa578063fbfee8761461021a57600080fd5b8063042bc3de146100c357806306fdde03146100e057806320606b70146101155780633be8ef3f1461013c57806350de7cf614610145578063aabb220a14610167575b600080fd5b6100cd62030d4081565b6040519081526020015b60405180910390f35b610108604051806040016040528060098152602001684e6f756e732044414f60b81b81525081565b6040516100d791906115ba565b6100cd7f8cad95687ba82c2ce50e74f7b754645e5117c3a5bec8151c0726d5857980a86681565b6100cd618ca081565b81801561015157600080fd5b50610165610160366004611640565b610225565b005b81801561017357600080fd5b506101656101823660046116b7565b610271565b81801561019357600080fd5b506101656101a23660046116ec565b6102ce565b6100cd642e90edd00081565b6100cd7f150214d74d59b7d1e90c73fc22ef3d991dd0a76b046543d4d80ab92d2a50328f81565b8180156101e657600080fd5b506101656101f5366004611754565b610310565b81801561020657600080fd5b5061016561021536600461179a565b610332565b6100cd637735940081565b61026986868686868080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250889250610593915050565b505050505050565b336000805160206119de8339815191528383610291878584846000610641565b6040805193845260ff90921660208401526001600160601b03169082015260806060820181905260009082015260a00160405180910390a2505050565b336000805160206119de83398151915285856102ee898584846000610641565b86866040516103019594939291906117f2565b60405180910390a25050505050565b61032c8484846040518060200160405280600081525085610593565b50505050565b60408051808201825260098152684e6f756e732044414f60b81b60209182015281517f8cad95687ba82c2ce50e74f7b754645e5117c3a5bec8151c0726d5857980a866818301527fe1dd93b3612547b4bb7c3d429f3df8508d84f5a4f63b5e2e44340b94698e6b3b81840152466060820152306080808301919091528351808303909101815260a0820184528051908301207f150214d74d59b7d1e90c73fc22ef3d991dd0a76b046543d4d80ab92d2a50328f60c083015260e0820189905260ff8816610100808401919091528451808403909101815261012083019094528351939092019290922061190160f01b6101408401526101428301829052610162830181905290916000906101820160408051601f198184030181528282528051602091820120600080855291840180845281905260ff8a169284019290925260608301889052608083018790529092509060019060a0016020604051602081039080840390855afa1580156104ab573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b0381166105265760405162461bcd60e51b815260206004820152602a60248201527f4e6f756e7344414f3a3a63617374566f746542795369673a20696e76616c6964604482015269207369676e617475726560b01b60648201526084015b60405180910390fd5b806001600160a01b03166000805160206119de8339815191528a8a61054f8e868f8f6000610641565b6040805193845260ff90921660208401526001600160601b03169082015260806060820181905260009082015260a00160405180910390a250505050505050505050565b60005a905060006105a78733888887610641565b9050336001600160a01b03166000805160206119de833981519152878784886040516105d69493929190611842565b60405180910390a263ffffffff8316156106205760405163ffffffff841690879033907f651cc9d78606507fdcfc4f37ec37a744d612b1d8f5a73564190577c4f0edb0b690600090a45b6001600160601b038116156106385761063882610804565b50505050505050565b60008061064e87866108f2565b9050600181600a8111156106645761066461187d565b0361067c5761067587868887610afa565b915061071f565b600981600a8111156106905761069061187d565b036106c25760ff8416156106b757604051639aeea66b60e01b815260040160405180910390fd5b610675878688610ea5565b60405162461bcd60e51b815260206004820152602c60248201527f4e6f756e7344414f3a3a63617374566f7465496e7465726e616c3a20766f746960448201526b1b99c81a5cc818db1bdcd95960a21b606482015260840161051d565b6000858152600b88016020908152604080832063ffffffff808816855260149091018352928190208151808301835290548085168252640100000000900484169281019290925280518082019091528151919290918291610782918791166118a9565b63ffffffff1681526020018260200151600161079e91906118c9565b63ffffffff9081169091526000978852600b90990160209081526040808920968b168952601490960181529490962086518154979095015189166401000000000267ffffffffffffffff1990971694909816939093179490941790955550929392505050565b476000819003610812575050565b600061082348642e90edd000611022565b905060006108373a63773594008401611022565b9050600061084e618ca05a87030162030d40611022565b9050600061085e82840286611022565b604051909150600090329083908381818185875af1925050503d80600081146108a3576040519150601f19603f3d011682016040523d82523d6000602084013e6108a8565b606091505b505060408051848152821515602082015291925032917ffabef36fd46c4c3a6ad676521be5367a4dfdbf3faa68d8e826003b1752d68f4f910160405180910390a250505050505050565b600081836008015410156109545760405162461bcd60e51b8152602060048201526024808201527f4e6f756e7344414f3a3a73746174653a20696e76616c69642070726f706f73616044820152631b081a5960e21b606482015260840161051d565b6000828152600b840160205260409020600e810154610100900460ff1615610980576008915050610af4565b600e81015460ff1615610997576002915050610af4565b601181015468010000000000000000900467ffffffffffffffff1643116109c257600a915050610af4565b806009015443116109d7576000915050610af4565b80600a015443116109ec576001915050610af4565b6011810154600160801b900467ffffffffffffffff164311610a12576009915050610af4565b610a1c848261103a565b15610a2b576003915050610af4565b8060040154600003610a41576004915050610af4565b600e81015462010000900460ff1615610a5e576007915050610af4565b610a688482611073565b6001600160a01b031663c1a287e26040518163ffffffff1660e01b8152600401602060405180830381865afa158015610aa5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ac991906118e6565b8160040154610ad891906118ff565b4210610ae8576006915050610af4565b6005915050610af4565b505b92915050565b600060028260ff161115610b765760405162461bcd60e51b815260206004820152603f60248201527f4e6f756e7344414f3a3a63617374566f7465447572696e67566f74696e67506560448201527f72696f64496e7465726e616c3a20696e76616c696420766f7465207479706500606482015260840161051d565b6000848152600b8601602090815260408083206001600160a01b0387168452600f8101909252909120805460ff1615610c215760405162461bcd60e51b815260206004820152604160248201527f4e6f756e7344414f3a3a63617374566f7465447572696e67566f74696e67506560448201527f72696f64496e7465726e616c3a20766f74657220616c726561647920766f74656064820152601960fa1b608482015260a40161051d565b600a870154600983015460405163782d6fe160e01b81526000926001600160a01b03169163782d6fe191610c6d918a916004016001600160a01b03929092168252602082015260400190565b602060405180830381865afa158015610c8a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cae9190611912565b905060008560ff16600103610cdf576010890154600a85015463ffffffff90911690610cdb90439061193b565b1090505b60008115610cf457610cf18a8661103a565b90505b8660ff16600003610d2257826001600160601b031685600c0154610d1891906118ff565b600c860155610d7a565b8660ff16600103610d5057826001600160601b031685600b0154610d4691906118ff565b600b860155610d7a565b8660ff16600203610d7a57826001600160601b031685600d0154610d7491906118ff565b600d8601555b818015610d845750805b8015610da357506011850154600160801b900467ffffffffffffffff16155b8015610db65750610db48a8661103a565b155b15610e595760108a0154600a860154610de791610de29164010000000090910463ffffffff16906118ff565b6110ab565b60118601805467ffffffffffffffff60801b1916600160801b67ffffffffffffffff93841681029190911791829055875460405191909204909216825263ffffffff16907f6553d98dd06f98670b24f69f718cdf9c8ec8e1cc42fb58b9c7908731322273479060200160405180910390a25b505081546001600160601b03821662010000026dffffffffffffffffffffffff00001960ff88166101000261ffff19909316929092176001179190911617909155915050949350505050565b6000828152600b8401602090815260408083206001600160a01b0385168452600f81019092528220805460ff1615610f375760405162461bcd60e51b815260206004820152602f60248201527f4e6f756e7344414f3a3a63617374566f7465496e7465726e616c3a20766f746560448201526e1c88185b1c9958591e481d9bdd1959608a1b606482015260840161051d565b600a860154600983015460405163782d6fe160e01b81526000926001600160a01b03169163782d6fe191610f839189916004016001600160a01b03929092168252602082015260400190565b602060405180830381865afa158015610fa0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fc49190611912565b825461ff001960ff196001600160601b038416620100008102919091166dffffffffffffffffffffffff00ff1990931692909217600117168455600c85015491925061100f916118ff565b600c909301929092555090509392505050565b60008183106110315781611033565b825b9392505050565b600b810154600c820154600091908111158061106b5750825461106890859063ffffffff9081169061111816565b81105b949350505050565b601381015460009060ff1615611097575060188201546001600160a01b0316610af4565b5060098201546001600160a01b0316610af4565b600067ffffffffffffffff8211156111145760405162461bcd60e51b815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203660448201526534206269747360d01b606482015260840161051d565b5090565b6000818152600b8301602052604081206010810154820361113e57600301549050610af4565b600c8101546010820154601183015461106b92919061116490889063ffffffff16611169565b61147e565b604080516060810182526000808252602082018190529181019190915260006111aa8360405180606001604052806040815260200161199e60409139611506565b600d85015490915060008190036112015760405180606001604052806111d38760070154611536565b61ffff1681526020016111e98760070154611536565b61ffff16815260006020909101529250610af4915050565b63ffffffff8216600d860161121760018461193b565b815481106112275761122761194e565b600091825260209091206002909102015463ffffffff16116112ba57600d850161125260018361193b565b815481106112625761126261194e565b6000918252602091829020604080516060810182526002939093029091016001015461ffff8082168452620100008204169383019390935264010000000090920463ffffffff16918101919091529250610af4915050565b8163ffffffff1685600d016000815481106112d7576112d761194e565b600091825260209091206002909102015463ffffffff16111561130c5760405180606001604052806111d38760070154611536565b60008061131a60018461193b565b90505b818111156114105760006002611333848461193b565b61133d9190611964565b611347908361193b565b9050600088600d0182815481106113605761136061194e565b60009182526020918290206040805180820182526002909302909101805463ffffffff9081168452825160608101845260019092015461ffff8082168452620100008204168387015264010000000090048116928201929092529282019290925280519092508782169116036113e157602001519550610af4945050505050565b805163ffffffff808816911610156113fb57819350611409565b61140660018361193b565b92505b505061131d565b86600d0182815481106114255761142561194e565b6000918252602091829020604080516060810182526002939093029091016001015461ffff8082168452620100008204169383019390935264010000000090920463ffffffff1691810191909152979650505050505050565b6000808361148e86612710611986565b6114989190611964565b90506000620f424082856040015163ffffffff166114b69190611986565b6114c09190611964565b9050600081856000015161ffff166114d891906118ff565b905060006114ee866020015161ffff1683611022565b90506114fa818861155b565b98975050505050505050565b60008163ffffffff84111561152e5760405162461bcd60e51b815260040161051d91906115ba565b509192915050565b600061ffff8211156111145760405163555abf0160e11b815260040160405180910390fd5b600061271061156a8484611986565b6110339190611964565b6000815180845260005b8181101561159a5760208185018101518683018201520161157e565b506000602082860101526020601f19601f83011685010191505092915050565b6020815260006110336020830184611574565b803560ff811681146115de57600080fd5b919050565b60008083601f8401126115f557600080fd5b50813567ffffffffffffffff81111561160d57600080fd5b60208301915083602082850101111561162557600080fd5b9250929050565b803563ffffffff811681146115de57600080fd5b60008060008060008060a0878903121561165957600080fd5b8635955060208701359450611670604088016115cd565b9350606087013567ffffffffffffffff81111561168c57600080fd5b61169889828a016115e3565b90945092506116ab90506080880161162c565b90509295509295509295565b6000806000606084860312156116cc57600080fd5b83359250602084013591506116e3604085016115cd565b90509250925092565b60008060008060006080868803121561170457600080fd5b853594506020860135935061171b604087016115cd565b9250606086013567ffffffffffffffff81111561173757600080fd5b611743888289016115e3565b969995985093965092949392505050565b6000806000806080858703121561176a57600080fd5b8435935060208501359250611781604086016115cd565b915061178f6060860161162c565b905092959194509250565b60008060008060008060c087890312156117b357600080fd5b86359550602087013594506117ca604088016115cd565b93506117d8606088016115cd565b92506080870135915060a087013590509295509295509295565b85815260ff851660208201526001600160601b038416604082015260806060820152816080820152818360a0830137600081830160a090810191909152601f909201601f19160101949350505050565b84815260ff841660208201526001600160601b03831660408201526080606082015260006118736080830184611574565b9695505050505050565b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052601160045260246000fd5b6001600160601b03818116838216019080821115610af257610af2611893565b63ffffffff818116838216019080821115610af257610af2611893565b6000602082840312156118f857600080fd5b5051919050565b80820180821115610af457610af4611893565b60006020828403121561192457600080fd5b81516001600160601b038116811461103357600080fd5b81810381811115610af457610af4611893565b634e487b7160e01b600052603260045260246000fd5b60008261198157634e487b7160e01b600052601260045260246000fd5b500490565b8082028115828204841417610af457610af461189356fe4e6f756e7344414f3a3a67657444796e616d696351756f72756d506172616d7341743a20626c6f636b206e756d62657220657863656564732033322062697473b8e138887d0aa13bab447e82de9d5c1777041ecd21ca36ba824ff1e6c07ddda4a264697066735822122043105a1adbc23b09950f1109a24d3d90a2f0b2ecc9d47ae2033b4ca57273b9bb64736f6c63430008170033", + "nonce": "0x144", + "chainId": "0xaa36a7", + "accessList": null, + "type": null + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0xd534b73edd763c42dd5102fb7ec5b3c7b45936edc12dde860bdd8b5c87cb257a", + "transactionType": "CREATE", + "contractName": "NounsDAOLogicV4", + "contractAddress": "0x017b4fd1a03308df03cb9a03a303fe9e6bc8ab7d", + "function": null, + "arguments": null, + "transaction": { + "from": "0xad36c32f3c28a9214adcf50a09998de1d3b0ee06", + "to": null, + "gas": "0x66a8ca", + "value": "0x0", + "input": "0x608060405234801561001057600080fd5b50615cac80620000216000396000f3fe6080604052600436106104405760003560e01c80637d17aa3a11610234578063c37522d41161012e578063da9427c4116100b6578063e48083fe1161007a578063e48083fe14610bd8578063ea3ecd0f14610d64578063f32293d214610d79578063f851a44014610d8e578063fe0d94c114610dac57610447565b8063da9427c414610c87578063da95691a14610ca7578063ddf0b00914610cc7578063e23a9a5214610ce7578063e2742e1814610d3757610447565b8063d27dd112116100fd578063d27dd11214610c01578063d33219b414610c21578063d8bff44014610c3f578063d93150be14610c5d578063da35c66414610c7257610447565b8063c37522d414610b96578063c3dd69eb14610bb8578063c82fbd0814610bd8578063cd0d9eac14610bec57610447565b806397242b8e116101bc578063aa0e23c711610180578063aa0e23c714610b07578063abb308b214610b34578063b112626314610ab1578063b58131b014610b61578063b5cd5bfa14610b7657610447565b806397242b8e14610a715780639a0dfb5314610a91578063a64e024a14610ab1578063a67d063514610ac7578063a9cf82f014610ae557610447565b806383cce0e11161020357806383cce0e1146109e457806384d1d199146109f95780638f1314b614610a1e5780638f1447d914610a3357806390f8c2f414610a5357610447565b80637d17aa3a146109725780637f5ef445146109945780637fa230bd146109af5780638136730f146109c457610447565b80633e2733341161034557806355ce73b1116102cd5780637217024c116102915780637217024c146108cb57806377388b70146108eb5780637757d18d146109205780637b3c71d31461093e5780637bdbe4d01461095e57610447565b806355ce73b1146108295780635678138814610849578063590c1f161461086957806364c0599514610889578063705cb335146108a957610447565b806344fac8f61161031457806344fac8f61461078757806347f4a077146107a757806349e857ea146107d457806353349413146107f45780635408e7f21461080957610447565b80633e273334146107055780633e4f49e61461071a5780633fde324d1461074757806340e58ee51461076757610447565b806328aa53e4116103c857806336a3b5781161039757806336a3b5781461067b57806338b1c2f6146106905780633932abb1146106b05780633b66c516146106c55780633bccf4fd146106e557610447565b806328aa53e4146105d95780632a4fa9fe146105f95780632de45f1814610619578063328dd9821461064b57610447565b806316f1b8cf1161040f57806316f1b8cf1461053757806317977c61146105575780631d28dec71461058d5780631e7b5d3a146105af578063215809ca146105c457610447565b8063013cf08b146104ad57806302a251a3146104e35780630f7b1f081461050257806314a67ea41461052257610447565b3661044757005b60003660606104a17302e813dbeaddefe9921f4a2093206aefef4453d66000368080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610dcc92505050565b80519350602001915050f35b3480156104b957600080fd5b506104cd6104c8366004613b3f565b610dfa565b6040516104da9190613b58565b60405180910390f35b3480156104ef57600080fd5b506005545b6040519081526020016104da565b34801561050e57600080fd5b506104f461051d366004613b3f565b610efe565b34801561052e57600080fd5b506006546104f4565b34801561054357600080fd5b506104f4610552366004613fa1565b610f0a565b34801561056357600080fd5b506104f4610572366004614095565b6001600160a01b03166000908152600c602052604090205490565b34801561059957600080fd5b506105ad6105a8366004613b3f565b610f27565b005b3480156105bb57600080fd5b506103e86104f4565b3480156105d057600080fd5b50611c206104f4565b3480156105e557600080fd5b506105ad6105f43660046140b2565b610f95565b34801561060557600080fd5b506104f4610614366004614174565b611408565b34801561062557600080fd5b50600a546001600160a01b03165b6040516001600160a01b0390911681526020016104da565b34801561065757600080fd5b5061066b610666366004613b3f565b611442565b6040516104da9493929190614374565b34801561068757600080fd5b506104f4611461565b34801561069c57600080fd5b506104f46106ab3660046143c1565b6114de565b3480156106bc57600080fd5b506004546104f4565b3480156106d157600080fd5b506104f46106e0366004614174565b611522565b3480156106f157600080fd5b506105ad6107003660046144a3565b61155c565b34801561071157600080fd5b506104f46115ed565b34801561072657600080fd5b5061073a610735366004613b3f565b611604565b6040516104da9190614507565b34801561075357600080fd5b506105ad610762366004614577565b611682565b34801561077357600080fd5b506105ad610782366004613b3f565b6116f2565b34801561079357600080fd5b506105ad6107a23660046145b8565b611731565b3480156107b357600080fd5b506107c76107c2366004613b3f565b611780565b6040516104da91906145e4565b3480156107e057600080fd5b506105ad6107ef366004614658565b6117a8565b34801561080057600080fd5b506016546104f4565b34801561081557600080fd5b506105ad61082436600461468d565b6117e4565b34801561083557600080fd5b506105ad6108443660046146c4565b611860565b34801561085557600080fd5b506105ad6108643660046145b8565b6118d3565b34801561087557600080fd5b506105ad61088436600461471a565b61191b565b34801561089557600080fd5b506105ad6108a43660046147b3565b61195f565b3480156108b557600080fd5b50601054600160201b900463ffffffff166104f4565b3480156108d757600080fd5b506104f46108e636600461480c565b6119d7565b3480156108f757600080fd5b50610900611a84565b604080516001600160a01b039384168152929091166020830152016104da565b34801561092c57600080fd5b506011546001600160a01b0316610633565b34801561094a57600080fd5b506105ad6109593660046147b3565b611b04565b34801561096a57600080fd5b50600a6104f4565b34801561097e57600080fd5b50601054600160401b900463ffffffff166104f4565b3480156109a057600080fd5b5060105463ffffffff166104f4565b3480156109bb57600080fd5b506104f4611b44565b3480156109d057600080fd5b506105ad6109df366004614912565b611b5b565b3480156109f057600080fd5b506007546104f4565b348015610a0557600080fd5b50601054600160601b90046001600160a01b0316610633565b348015610a2a57600080fd5b506104f4611b9d565b348015610a3f57600080fd5b506105ad610a4e366004614980565b611ba9565b348015610a5f57600080fd5b506018546001600160a01b0316610633565b348015610a7d57600080fd5b506105ad610a8c3660046149bc565b611bfd565b348015610a9d57600080fd5b506104f4610aac366004614af2565b611c97565b348015610abd57600080fd5b50620189c06104f4565b348015610ad357600080fd5b50600e546001600160a01b0316610633565b348015610af157600080fd5b50610afa611d20565b6040516104da9190614baa565b348015610b1357600080fd5b50610b27610b22366004614c06565b611dc5565b6040516104da9190614cd8565b348015610b4057600080fd5b50610b54610b4f366004613b3f565b611dd8565b6040516104da9190614d9f565b348015610b6d57600080fd5b506104f4611e84565b348015610b8257600080fd5b506105ad610b9136600461471a565b611e99565b348015610ba257600080fd5b50610bab611edd565b6040516104da9190614dad565b348015610bc457600080fd5b506105ad610bd3366004614dc0565b611f42565b348015610be457600080fd5b5060016104f4565b348015610bf857600080fd5b506104f4611f84565b348015610c0d57600080fd5b506105ad610c1c366004614658565b611fbf565b348015610c2d57600080fd5b506009546001600160a01b0316610633565b348015610c4b57600080fd5b506003546001600160a01b0316610633565b348015610c6957600080fd5b506015546104f4565b348015610c7e57600080fd5b506008546104f4565b348015610c9357600080fd5b506105ad610ca2366004614e39565b611ffb565b348015610cb357600080fd5b506104f4610cc23660046143c1565b612041565b348015610cd357600080fd5b506105ad610ce2366004613b3f565b612052565b348015610cf357600080fd5b50610d07610d02366004614f38565b612091565b6040805182511515815260208084015160ff1690820152918101516001600160601b0316908201526060016104da565b348015610d4357600080fd5b50610d57610d52366004613b3f565b61211d565b6040516104da9190614f68565b348015610d7057600080fd5b506019546104f4565b348015610d8557600080fd5b506017546104f4565b348015610d9a57600080fd5b506000546001600160a01b0316610633565b348015610db857600080fd5b506105ad610dc7366004613b3f565b612242565b6060610df18383604051806060016040528060278152602001615c1060279139612281565b90505b92915050565b610e82604051806101e001604052806000815260200160006001600160a01b03168152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160001515815260200160001515815260200160001515815260200160008152602001600081525090565b604051631257ca3b60e31b815260006004820152602481018390527381ede38efc867818bf77978514f5dca76c20a050906392be51d8906044016101e060405180830381865af4158015610eda573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610df491906150ad565b6000610df48183612350565b6000610f1c87878787878760006119d7565b979650505050505050565b604051632cbebd3560e21b815260006004820152602481018290527381ede38efc867818bf77978514f5dca76c20a0509063b2faf4d4906044015b60006040518083038186803b158015610f7a57600080fd5b505af4158015610f8e573d6000803e3d6000fd5b5050505050565b6009546001600160a01b031615610fbf57604051630205737f60e61b815260040160405180910390fd5b6000546001600160a01b03163314610fea57604051633057182d60e21b815260040160405180910390fd5b6001600160a01b03871661101157604051637330d04160e11b815260040160405180910390fd5b6001600160a01b0386166110385760405163d2ef0d7160e01b815260040160405180910390fd5b6040516303a8b66360e21b8152823560048201527302e813dbeaddefe9921f4a2093206aefef4453d690630ea2d98c9060240160006040518083038186803b15801561108357600080fd5b505af4158015611097573d6000803e3d6000fd5b5050604051630efd8dad60e11b8152602085013560048201527302e813dbeaddefe9921f4a2093206aefef4453d69250631dfb1b5a915060240160006040518083038186803b1580156110e957600080fd5b505af41580156110fd573d6000803e3d6000fd5b5050604080516397d048e560e01b81529085013560048201527302e813dbeaddefe9921f4a2093206aefef4453d692506397d048e5915060240160006040518083038186803b15801561114f57600080fd5b505af4158015611163573d6000803e3d6000fd5b5050600980546001600160a01b03199081166001600160a01b038c811691909117909255600a805482168b8416179055601080546001600160601b0316600160601b8b85160217905560118054821689841617905560038054909116918716919091179055507302e813dbeaddefe9921f4a2093206aefef4453d6905063ec91deda6111f26020840184615186565b6112026040850160208601615186565b61121260608601604087016151a1565b6040516001600160e01b031960e086901b16815261ffff938416600482015292909116602483015263ffffffff16604482015260640160006040518083038186803b15801561126057600080fd5b505af4158015611274573d6000803e3d6000fd5b505050507302e813dbeaddefe9921f4a2093206aefef4453d663e25607728360600160208101906112a591906151a1565b6040516001600160e01b031960e084901b16815263ffffffff91909116600482015260240160006040518083038186803b1580156112e257600080fd5b505af41580156112f6573d6000803e3d6000fd5b505050507302e813dbeaddefe9921f4a2093206aefef4453d663e5eb5abf83608001602081019061132791906151a1565b6040516001600160e01b031960e084901b16815263ffffffff91909116600482015260240160006040518083038186803b15801561136457600080fd5b505af4158015611378573d6000803e3d6000fd5b505050507302e813dbeaddefe9921f4a2093206aefef4453d66374b157b88360a00160208101906113a991906151a1565b6040516001600160e01b031960e084901b16815263ffffffff9190911660048201526024015b60006040518083038186803b1580156113e757600080fd5b505af41580156113fb573d6000803e3d6000fd5b5050505050505050505050565b6000610f1c604051806080016040528089815260200188815260200187815260200186815250848460006123a9909392919063ffffffff16565b60608080806114526000866124fa565b93509350935093509193509193565b6040516319244b1760e01b815260006004820181905290733f08ce1a659c34737d1a1aae437bf5a99a1857be906319244b17906024015b602060405180830381865af41580156114b5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114d991906151bc565b905090565b60006115186040518060800160405280888152602001878152602001868152602001858152508360008061278f909392919063ffffffff16565b9695505050505050565b6000610f1c6040518060800160405280898152602001888152602001878152602001868152508484600061278f909392919063ffffffff16565b60405163f57e66d160e01b8152600060048201526024810186905260ff8086166044830152841660648201526084810183905260a481018290527330656985039923eaa1ebb968fe84a1277581f6029063f57e66d19060c4015b60006040518083038186803b1580156115ce57600080fd5b505af41580156115e2573d6000803e3d6000fd5b505050505050505050565b60006114d96115fc6000612806565b600090612982565b6040516373d0ed2f60e01b815260006004820181905260248201839052907381ede38efc867818bf77978514f5dca76c20a050906373d0ed2f90604401602060405180830381865af415801561165e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610df491906151d5565b60405163b7aa3e5760e01b81527381ede38efc867818bf77978514f5dca76c20a0509063b7aa3e57906116be906000908690869060040161521f565b60006040518083038186803b1580156116d657600080fd5b505af41580156116ea573d6000803e3d6000fd5b505050505050565b604051631e7296df60e11b815260006004820152602481018290527381ede38efc867818bf77978514f5dca76c20a05090633ce52dbe90604401610f62565b604051637082ec2560e11b81526000600482018190526024820184905260ff8316604483015260648201527330656985039923eaa1ebb968fe84a1277581f6029063e105d84a906084016116be565b6040805160608101825260008082526020820181905291810191909152610df460008361299c565b6040516302bbd42360e11b8152733f08ce1a659c34737d1a1aae437bf5a99a1857be90630577a846906116be9060009086908690600401615274565b6040516383478b4360e01b81527381ede38efc867818bf77978514f5dca76c20a050906383478b4390611828906000908a908a908a908a908a908a9060040161528e565b60006040518083038186803b15801561184057600080fd5b505af4158015611854573d6000803e3d6000fd5b50505050505050505050565b60405163575535f360e11b8152733f08ce1a659c34737d1a1aae437bf5a99a1857be9063aeaa6be69061189e90600090879087908790600401615309565b60006040518083038186803b1580156118b657600080fd5b505af41580156118ca573d6000803e3d6000fd5b50505050505050565b60405163555d910560e11b8152600060048201526024810183905260ff821660448201527330656985039923eaa1ebb968fe84a1277581f6029063aabb220a906064016116be565b604051633d43469f60e11b8152733f08ce1a659c34737d1a1aae437bf5a99a1857be90637a868d3e90611828906000908a908a908a908a908a908a9060040161533c565b60405163286f3e7b60e11b81527330656985039923eaa1ebb968fe84a1277581f602906350de7cf6906119a1906000908890889088908890859060040161537e565b60006040518083038186803b1580156119b957600080fd5b505af41580156119cd573d6000803e3d6000fd5b5050505050505050565b60408051608081018252878152602081018790528082018690526060810185905290516320660f5360e01b81526000917381ede38efc867818bf77978514f5dca76c20a050916320660f5391611a379185918d9189908990600401615516565b602060405180830381865af4158015611a54573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a7891906151bc565b98975050505050505050565b6040516338251d8960e11b8152600060048201819052908190733f08ce1a659c34737d1a1aae437bf5a99a1857be9063704a3b12906024016040805180830381865af4158015611ad8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611afc919061556e565b915091509091565b60405163b73a99c760e01b81527330656985039923eaa1ebb968fe84a1277581f6029063b73a99c7906119a190600090889088908890889060040161559d565b60006114d9611b536000612806565b600090612cae565b60405163286f3e7b60e11b81527330656985039923eaa1ebb968fe84a1277581f602906350de7cf6906115b6906000908990899089908990899060040161537e565b60006114d96000612806565b604051637082ec2560e11b8152600060048201526024810184905260ff8316604482015263ffffffff821660648201527330656985039923eaa1ebb968fe84a1277581f6029063e105d84a9060840161189e565b604080516080810182528781526020810187905280820186905260608101859052905163f9df1e1960e01b81527381ede38efc867818bf77978514f5dca76c20a0509163f9df1e1991611c5d916000918d918d91899089906004016155c6565b60006040518083038186803b158015611c7557600080fd5b505af4158015611c89573d6000803e3d6000fd5b505050505050505050505050565b60405163bb29607560e01b815260009073970583ad744c3f73eafc7f25591373ba17bdd2869063bb29607590611cd59087908790879060040161562c565b602060405180830381865af4158015611cf2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d1691906151bc565b90505b9392505050565b60606000600d01805480602002602001604051908101604052809291908181526020016000905b82821015611dbc57600084815260209081902060408051808201825260028602909201805463ffffffff9081168452825160608101845260019283015461ffff80821683526201000082041682880152600160201b900490911692810192909252828401919091529083529092019101611d47565b50505050905090565b6060611a78600089898989898989612ccb565b611e0b60408051808201825260008082528251606081018452818152602081810183905293810191909152909182015290565b600d805483908110611e1f57611e1f615669565b60009182526020918290206040805180820182526002909302909101805463ffffffff9081168452825160608101845260019092015461ffff80821684526201000082041683870152600160201b900416918101919091529181019190915292915050565b60006114d9611e91611b9d565b6000906130c3565b604051633d99f84560e21b8152733f08ce1a659c34737d1a1aae437bf5a99a1857be9063f667e11490611828906000908a908a908a908a908a908a9060040161533c565b60606000601201805480602002602001604051908101604052809291908181526020018280548015611f3857602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311611f1a575b5050505050905090565b6040516316147f8760e31b81527381ede38efc867818bf77978514f5dca76c20a0509063b0a3fc38906115b6906000908990899089908990899060040161567f565b6040516309ea0cfb60e11b815260006004820181905290733f08ce1a659c34737d1a1aae437bf5a99a1857be906313d419f690602401611498565b604051636055f93560e01b8152733f08ce1a659c34737d1a1aae437bf5a99a1857be90636055f935906116be9060009086908690600401615274565b604051637b55bff360e01b81527381ede38efc867818bf77978514f5dca76c20a05090637b55bff3906113cf906000908b908b908b908b908b908b908b906004016156b2565b600061151886868686866000611408565b60405163179aac6b60e21b815260006004820152602481018290527381ede38efc867818bf77978514f5dca76c20a05090635e6ab1ac90604401610f62565b604080516060808201835260008083526020808401829052838501829052845180840186528281528082018390528501829052868252600b81528482206001600160a01b0387168352600f01815290849020845192830185525460ff80821615158452610100820416918301919091526201000090046001600160601b03169281019290925290610df1565b6121c36040518061026001604052806000815260200160006001600160a01b03168152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160001515815260200160001515815260200160001515815260200160008152602001600081526020016060815260200160008152602001600081526020016000151581525090565b60405163ddb6398360e01b815260006004820152602481018390527381ede38efc867818bf77978514f5dca76c20a0509063ddb6398390604401600060405180830381865af415801561221a573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610df491908101906157ad565b60405163370d357760e01b815260006004820152602481018290527381ede38efc867818bf77978514f5dca76c20a0509063370d357790604401610f62565b6060833b6122e55760405162461bcd60e51b815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f6044820152651b9d1c9858dd60d21b60648201526084015b60405180910390fd5b600080856001600160a01b0316856040516123009190615905565b600060405180830381855af49150503d806000811461233b576040519150601f19603f3d011682016040523d82523d6000602084013e612340565b606091505b50915091506115188282866130d3565b6000818152600b8301602052604081206010810154820361237657600301549050610df4565b600c810154601082015460118301546123a192919061239c90889063ffffffff1661299c565b61310c565b949350505050565b6000806123b586612806565b600a87015490915060009061245c9088906001600160a01b031663782d6fe1336123e0600143615937565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401602060405180830381865afa158015612429573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061244d919061594a565b6001600160601b031684613188565b9050612467866131b6565b612471873361324d565b6008870154612481906001615973565b600888018190556000906124949061330a565b905060006124a6898385878c8b613373565b336000908152600c8b016020908152604080832063ffffffff87169055805192835290820190529091506124e89082906124e08c88612982565b8b8b8b61353a565b5063ffffffff16979650505050505050565b606080606080600086600b0160008781526020019081526020016000209050806005018160060182600701836008018380548060200260200160405190810160405280929190818152602001828054801561257e57602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311612560575b50505050509350828054806020026020016040519081016040528092919081815260200182805480156125d057602002820191906000526020600020905b8154815260200190600101908083116125bc575b5050505050925081805480602002602001604051908101604052809291908181526020016000905b828210156126a457838290600052602060002001805461261790615986565b80601f016020809104026020016040519081016040528092919081815260200182805461264390615986565b80156126905780601f1061266557610100808354040283529160200191612690565b820191906000526020600020905b81548152906001019060200180831161267357829003601f168201915b5050505050815260200190600101906125f8565b50505050915080805480602002602001604051908101604052809291908181526020016000905b828210156127775783829060005260206000200180546126ea90615986565b80601f016020809104026020016040519081016040528092919081815260200182805461271690615986565b80156127635780601f1061273857610100808354040283529160200191612763565b820191906000526020600020905b81548152906001019060200180831161274657829003601f168201915b5050505050815260200190600101906126cb565b50505050905094509450945094505092959194509250565b60008061279e868686866123a9565b6000818152600b880160205260409081902060138101805460ff191660011790559051919250907f9fb4e5204ac554428e5c744568b78732c229c76c0b5eaebdca7171c41366f6af906127f49084815260200190565b60405180910390a15095945050505050565b600081601001600c9054906101000a90046001600160a01b03166001600160a01b0316639b3c1e226040518163ffffffff1660e01b8152600401602060405180830381865afa15801561285d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061288191906151bc565b600a83015460098401546040516370a0823160e01b81526001600160a01b0391821660048201529116906370a0823190602401602060405180830381865afa1580156128d1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128f591906151bc565b83600a0160009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561294a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061296e91906151bc565b6129789190615937565b610df49190615937565b6000610df1612991844361299c565b5161ffff1683613614565b604080516060810182526000808252602082018190529181019190915260006129dd83604051806060016040528060408152602001615c376040913961362d565b600d8501549091506000819003612a34576040518060600160405280612a06876007015461365d565b61ffff168152602001612a1c876007015461365d565b61ffff16815260006020909101529250610df4915050565b63ffffffff8216600d8601612a4a600184615937565b81548110612a5a57612a5a615669565b600091825260209091206002909102015463ffffffff1611612aec57600d8501612a85600183615937565b81548110612a9557612a95615669565b6000918252602091829020604080516060810182526002939093029091016001015461ffff80821684526201000082041693830193909352600160201b90920463ffffffff16918101919091529250610df4915050565b8163ffffffff1685600d01600081548110612b0957612b09615669565b600091825260209091206002909102015463ffffffff161115612b3e576040518060600160405280612a06876007015461365d565b600080612b4c600184615937565b90505b81811115612c415760006002612b658484615937565b612b6f91906159c0565b612b799083615937565b9050600088600d018281548110612b9257612b92615669565b60009182526020918290206040805180820182526002909302909101805463ffffffff9081168452825160608101845260019092015461ffff80821684526201000082041683870152600160201b9004811692820192909252928201929092528051909250878216911603612c1257602001519550610df4945050505050565b805163ffffffff80881691161015612c2c57819350612c3a565b612c37600183615937565b92505b5050612b4f565b86600d018281548110612c5657612c56615669565b6000918252602091829020604080516060810182526002939093029091016001015461ffff80821684526201000082041693830193909352600160201b90920463ffffffff1691810191909152979650505050505050565b6000610df1612cbd844361299c565b6020015161ffff1683613614565b606087871015612d275760405162461bcd60e51b815260206004820152602160248201527f6c61737450726f706f73616c4964203e3d20666972737450726f706f73616c496044820152601960fa1b60648201526084016122dc565b6000612d338989615937565b612d3e906001615973565b90506000816001600160401b03811115612d5a57612d5a613c1e565b604051908082528060200260200182016040528015612de057816020015b612dcd60405180610120016040528060008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600063ffffffff168152602001606081525090565b815260200190600190039081612d785790505b509050600080612e03604051806040016040528060008152602001600081525090565b8c5b8c81116130b0578e600b01600082815260200190815260200160002093508a8015612e345750600e84015460ff165b6130a057600a84015482526011840154600160801b90046001600160401b031660208301528915612ed5576000612e7383600001518460200151613682565b9050804311612ed35760405162461bcd60e51b815260206004820152602660248201527f616c6c2070726f706f73616c73206d75737420626520646f6e65207769746820604482015265766f74696e6760d01b60648201526084016122dc565b505b600084600b015490506000856010015490506127108e61ffff1682612efa91906159e2565b612f0491906159c0565b821015612f125750506130a0565b60008a6001600160401b03811115612f2c57612f2c613c1e565b604051908082528060200260200182016040528015612f7157816020015b6040805180820190915260008082526020820152815260200190600190039081612f4a5790505b50905060005b8b81101561300b578760140160008e8e84818110612f9757612f97615669565b9050602002016020810190612fac91906151a1565b63ffffffff908116825260208083019390935260409182016000208251808401909352548082168352600160201b900416918101919091528251839083908110612ff857612ff8615669565b6020908102919091010152600101612f77565b5060408051610120810182528651815260208088015190820152908101849052600c8801546060820152600d880154608082015260a08101839052601188015463ffffffff600160201b91829004811660c08401528954919091041660e08201526101008101829052888761307f816159f9565b98508151811061309157613091615669565b60200260200101819052505050505b6130a9816159f9565b9050612e05565b50508252509a9950505050505050505050565b6000610df1836006015483613614565b606083156130e2575081611d19565b8251156130f25782518084602001fd5b8160405162461bcd60e51b81526004016122dc9190615a12565b6000808361311c866127106159e2565b61312691906159c0565b90506000620f424082856040015163ffffffff1661314491906159e2565b61314e91906159c0565b9050600081856000015161ffff166131669190615973565b9050600061317c866020015161ffff1683613698565b9050611a788188613614565b600061319484836130c3565b9050808311611d195760405163ead8241560e01b815260040160405180910390fd5b6020810151518151511415806131d3575060408101515181515114155b806131e5575060608101515181515114155b156132035760405163ccb0ce3f60e01b815260040160405180910390fd5b80515160000361322657604051630f24cd7360e01b815260040160405180910390fd5b805151600a101561324a576040516308e3b1eb60e11b815260040160405180910390fd5b50565b6001600160a01b0381166000908152600c83016020526040902054801561330557600061327a84836136a7565b9050600981600a811115613290576132906144f1565b14806132ad5750600181600a8111156132ab576132ab6144f1565b145b806132c95750600081600a8111156132c7576132c76144f1565b145b806132e55750600a81600a8111156132e3576132e36144f1565b145b15613303576040516306bee79560e01b815260040160405180910390fd5b505b505050565b600063ffffffff82111561336f5760405162461bcd60e51b815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203360448201526532206269747360d01b60648201526084016122dc565b5090565b6010860154600090819061339d9061339890600160401b900463ffffffff1643615973565b6138a0565b905060008860040154826001600160401b03166133ba9190615973565b905060008960050154826133ce9190615973565b63ffffffff808b166000818152600b8e01602090815260409091208054938a16600160201b0267ffffffffffffffff199094169092179290921781556001810180546001600160a01b03191633179055600281018b90558851805191975092935061343f9260058801920190613976565b50602080870151805161345892600688019201906139d7565b5060408601518051613474916007870191602090910190613a12565b5060608601518051613490916008870191602090910190613a64565b5060098401829055600a8401819055601084018790556134af4361330a565b60118501805463ffffffff191663ffffffff929092169190911790556134d44261330a565b6011850180546001600160401b03909516600160401b026fffffffffffffffff00000000000000001963ffffffff93909316600160201b02929092166fffffffffffffffffffffffff000000001990951694909417179092555090979650505050505050565b855483516020850151604080870151606088015160098c0154600a8d015493517f7d84a6263ae0d98d3329bd7b46bb4e8d6f98cd35a7adb45c274c8b7fd5ebd5e09761359d9763ffffffff90911696339691959094909390929091908c90615a25565b60405180910390a185546011870154600288015460405163ffffffff808616947fd9d12651716feaac10e3b79bd2960ad42ebfd84969b71a2e226ec99972a8712e946136049491909216928b926001600160401b03600160401b9091041691908b90615ac3565b60405180910390a2505050505050565b600061271061362384846159e2565b610df191906159c0565b60008163ffffffff8411156136555760405162461bcd60e51b81526004016122dc9190615a12565b509192915050565b600061ffff82111561336f5760405163555abf0160e11b815260040160405180910390fd5b60008183116136915781610df1565b5090919050565b60008183106136915781610df1565b600081836008015410156137095760405162461bcd60e51b8152602060048201526024808201527f4e6f756e7344414f3a3a73746174653a20696e76616c69642070726f706f73616044820152631b081a5960e21b60648201526084016122dc565b6000828152600b840160205260409020600e810154610100900460ff1615613735576008915050610df4565b600e81015460ff161561374c576002915050610df4565b6011810154600160401b90046001600160401b0316431161377157600a915050610df4565b80600901544311613786576000915050610df4565b80600a0154431161379b576001915050610df4565b6011810154600160801b90046001600160401b031643116137c0576009915050610df4565b6137ca8482613908565b156137d9576003915050610df4565b80600401546000036137ef576004915050610df4565b600e81015462010000900460ff161561380c576007915050610df4565b613816848261393e565b6001600160a01b031663c1a287e26040518163ffffffff1660e01b8152600401602060405180830381865afa158015613853573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061387791906151bc565b81600401546138869190615973565b4210613896576006915050610df4565b6005915050610df4565b60006001600160401b0382111561336f5760405162461bcd60e51b815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203660448201526534206269747360d01b60648201526084016122dc565b600b810154600c82015460009190811115806123a15750825461393690859063ffffffff9081169061235016565b119392505050565b601381015460009060ff1615613962575060188201546001600160a01b0316610df4565b5060098201546001600160a01b0316610df4565b8280548282559060005260206000209081019282156139cb579160200282015b828111156139cb57825182546001600160a01b0319166001600160a01b03909116178255602090920191600190910190613996565b5061336f929150613ab6565b8280548282559060005260206000209081019282156139cb579160200282015b828111156139cb5782518255916020019190600101906139f7565b828054828255906000526020600020908101928215613a58579160200282015b82811115613a585782518290613a489082615b50565b5091602001919060010190613a32565b5061336f929150613acb565b828054828255906000526020600020908101928215613aaa579160200282015b82811115613aaa5782518290613a9a9082615b50565b5091602001919060010190613a84565b5061336f929150613ae8565b5b8082111561336f5760008155600101613ab7565b8082111561336f576000613adf8282613b05565b50600101613acb565b8082111561336f576000613afc8282613b05565b50600101613ae8565b508054613b1190615986565b6000825580601f10613b21575050565b601f01602090049060005260206000209081019061324a9190613ab6565b600060208284031215613b5157600080fd5b5035919050565b815181526020808301516101e0830191613b7c908401826001600160a01b03169052565b5060408301516040830152606083015160608301526080830151608083015260a083015160a083015260c083015160c083015260e083015160e083015261010080840151818401525061012080840151818401525061014080840151613be58285018215159052565b505061016083810151151590830152610180808401511515908301526101a080840151908301526101c092830151929091019190915290565b634e487b7160e01b600052604160045260246000fd5b604051606081016001600160401b0381118282101715613c5657613c56613c1e565b60405290565b6040516101e081016001600160401b0381118282101715613c5657613c56613c1e565b60405161026081016001600160401b0381118282101715613c5657613c56613c1e565b604051601f8201601f191681016001600160401b0381118282101715613cca57613cca613c1e565b604052919050565b60006001600160401b03821115613ceb57613ceb613c1e565b5060051b60200190565b600082601f830112613d0657600080fd5b81356001600160401b03811115613d1f57613d1f613c1e565b613d32601f8201601f1916602001613ca2565b818152846020838601011115613d4757600080fd5b816020850160208301376000918101602001919091529392505050565b6001600160a01b038116811461324a57600080fd5b600082601f830112613d8a57600080fd5b81356020613d9f613d9a83613cd2565b613ca2565b82815260059290921b84018101918181019086841115613dbe57600080fd5b8286015b84811015613e505780356001600160401b0380821115613de25760008081fd5b908801906060828b03601f1901811315613dfc5760008081fd5b613e04613c34565b8784013583811115613e165760008081fd5b613e248d8a83880101613cf5565b8252506040925082840135613e3881613d64565b81890152920135908201528352918301918301613dc2565b509695505050505050565b600082601f830112613e6c57600080fd5b81356020613e7c613d9a83613cd2565b8083825260208201915060208460051b870101935086841115613e9e57600080fd5b602086015b84811015613e50578035613eb681613d64565b8352918301918301613ea3565b600082601f830112613ed457600080fd5b81356020613ee4613d9a83613cd2565b8083825260208201915060208460051b870101935086841115613f0657600080fd5b602086015b84811015613e505780358352918301918301613f0b565b600082601f830112613f3357600080fd5b81356020613f43613d9a83613cd2565b82815260059290921b84018101918181019086841115613f6257600080fd5b8286015b84811015613e505780356001600160401b03811115613f855760008081fd5b613f938986838b0101613cf5565b845250918301918301613f66565b60008060008060008060c08789031215613fba57600080fd5b86356001600160401b0380821115613fd157600080fd5b613fdd8a838b01613d79565b97506020890135915080821115613ff357600080fd5b613fff8a838b01613e5b565b9650604089013591508082111561401557600080fd5b6140218a838b01613ec3565b9550606089013591508082111561403757600080fd5b6140438a838b01613f22565b9450608089013591508082111561405957600080fd5b6140658a838b01613f22565b935060a089013591508082111561407b57600080fd5b5061408889828a01613cf5565b9150509295509295509295565b6000602082840312156140a757600080fd5b8135611d1981613d64565b60008060008060008060008789036101c08112156140cf57600080fd5b88356140da81613d64565b975060208901356140ea81613d64565b965060408901356140fa81613d64565b9550606089013561410a81613d64565b9450608089013561411a81613d64565b935060c0609f198201121561412e57600080fd5b60a089019250606061015f198201121561414757600080fd5b506101608801905092959891949750929550565b803563ffffffff8116811461416f57600080fd5b919050565b60008060008060008060c0878903121561418d57600080fd5b86356001600160401b03808211156141a457600080fd5b6141b08a838b01613e5b565b975060208901359150808211156141c657600080fd5b6141d28a838b01613ec3565b965060408901359150808211156141e857600080fd5b6141f48a838b01613f22565b9550606089013591508082111561420a57600080fd5b6142168a838b01613f22565b9450608089013591508082111561422c57600080fd5b5061423989828a01613cf5565b92505061424860a0880161415b565b90509295509295509295565b60008151808452602080850194506020840160005b8381101561428e5781516001600160a01b031687529582019590820190600101614269565b509495945050505050565b60008151808452602080850194506020840160005b8381101561428e578151875295820195908201906001016142ae565b60005b838110156142e55781810151838201526020016142cd565b50506000910152565b600081518084526143068160208601602086016142ca565b601f01601f19169290920160200192915050565b60008282518085526020808601955060208260051b8401016020860160005b8481101561436757601f198684030189526143558383516142ee565b98840198925090830190600101614339565b5090979650505050505050565b6080815260006143876080830187614254565b82810360208401526143998187614299565b905082810360408401526143ad818661431a565b90508281036060840152610f1c818561431a565b600080600080600060a086880312156143d957600080fd5b85356001600160401b03808211156143f057600080fd5b6143fc89838a01613e5b565b9650602088013591508082111561441257600080fd5b61441e89838a01613ec3565b9550604088013591508082111561443457600080fd5b61444089838a01613f22565b9450606088013591508082111561445657600080fd5b61446289838a01613f22565b9350608088013591508082111561447857600080fd5b5061448588828901613cf5565b9150509295509295909350565b803560ff8116811461416f57600080fd5b600080600080600060a086880312156144bb57600080fd5b853594506144cb60208701614492565b93506144d960408701614492565b94979396509394606081013594506080013592915050565b634e487b7160e01b600052602160045260246000fd5b60208101600b831061452957634e487b7160e01b600052602160045260246000fd5b91905290565b60008083601f84011261454157600080fd5b5081356001600160401b0381111561455857600080fd5b60208301915083602082850101111561457057600080fd5b9250929050565b6000806020838503121561458a57600080fd5b82356001600160401b038111156145a057600080fd5b6145ac8582860161452f565b90969095509350505050565b600080604083850312156145cb57600080fd5b823591506145db60208401614492565b90509250929050565b815161ffff90811682526020808401519091169082015260408083015163ffffffff169082015260608101610df4565b60008083601f84011261462657600080fd5b5081356001600160401b0381111561463d57600080fd5b6020830191508360208260051b850101111561457057600080fd5b6000806020838503121561466b57600080fd5b82356001600160401b0381111561468157600080fd5b6145ac85828601614614565b60008060008060008060c087890312156146a657600080fd5b8635955060208701356001600160401b0380821115613ff357600080fd5b6000806000604084860312156146d957600080fd5b83356001600160401b038111156146ef57600080fd5b6146fb86828701614614565b909450925050602084013561470f81613d64565b809150509250925092565b6000806000806000806060878903121561473357600080fd5b86356001600160401b038082111561474a57600080fd5b6147568a838b01614614565b9098509650602089013591508082111561476f57600080fd5b61477b8a838b01614614565b9096509450604089013591508082111561479457600080fd5b506147a189828a0161452f565b979a9699509497509295939492505050565b600080600080606085870312156147c957600080fd5b843593506147d960208601614492565b925060408501356001600160401b038111156147f457600080fd5b6148008782880161452f565b95989497509550505050565b600080600080600080600060e0888a03121561482757600080fd5b87356001600160401b038082111561483e57600080fd5b61484a8b838c01613d79565b985060208a013591508082111561486057600080fd5b61486c8b838c01613e5b565b975060408a013591508082111561488257600080fd5b61488e8b838c01613ec3565b965060608a01359150808211156148a457600080fd5b6148b08b838c01613f22565b955060808a01359150808211156148c657600080fd5b6148d28b838c01613f22565b945060a08a01359150808211156148e857600080fd5b506148f58a828b01613cf5565b92505061490460c0890161415b565b905092959891949750929550565b60008060008060006080868803121561492a57600080fd5b8535945061493a60208701614492565b935060408601356001600160401b0381111561495557600080fd5b6149618882890161452f565b909450925061497490506060870161415b565b90509295509295909350565b60008060006060848603121561499557600080fd5b833592506149a560208501614492565b91506149b36040850161415b565b90509250925092565b600080600080600080600080610100898b0312156149d957600080fd5b8835975060208901356001600160401b03808211156149f757600080fd5b614a038c838d01613d79565b985060408b0135915080821115614a1957600080fd5b614a258c838d01613e5b565b975060608b0135915080821115614a3b57600080fd5b614a478c838d01613ec3565b965060808b0135915080821115614a5d57600080fd5b614a698c838d01613f22565b955060a08b0135915080821115614a7f57600080fd5b614a8b8c838d01613f22565b945060c08b0135915080821115614aa157600080fd5b614aad8c838d01613cf5565b935060e08b0135915080821115614ac357600080fd5b50614ad08b828c01613cf5565b9150509295985092959890939650565b803561ffff8116811461416f57600080fd5b600080600083850360a0811215614b0857600080fd5b84359350602085013592506060603f1982011215614b2557600080fd5b50614b2e613c34565b614b3a60408601614ae0565b8152614b4860608601614ae0565b6020820152614b596080860161415b565b6040820152809150509250925092565b63ffffffff81511682526020810151613305602084018261ffff8082511683528060208301511660208401525063ffffffff60408201511660408301525050565b6020808252825182820181905260009190848201906040850190845b81811015614bec57614bd9838551614b69565b9284019260809290920191600101614bc6565b50909695505050505050565b801515811461324a57600080fd5b600080600080600080600060c0888a031215614c2157600080fd5b8735965060208801359550614c3860408901614ae0565b94506060880135614c4881614bf8565b93506080880135614c5881614bf8565b925060a08801356001600160401b03811115614c7357600080fd5b614c7f8a828b01614614565b989b979a50959850939692959293505050565b60008151808452602080850194506020840160005b8381101561428e578151805163ffffffff908116895290840151168388015260409096019590820190600101614ca7565b600060208083018184528085518083526040925060408601915060408160051b87010184880160005b83811015614d9157888303603f1901855281518051845287810151888501528681015187850152606080820151908501526080808201519085015260a0808201519085015260c0808201519085015260e08082015163ffffffff16908501526101009081015161012091850182905290614d7d81860183614c92565b968901969450505090860190600101614d01565b509098975050505050505050565b60808101610df48284614b69565b602081526000610df16020830184614254565b600080600080600060608688031215614dd857600080fd5b8535945060208601356001600160401b0380821115614df657600080fd5b614e0289838a0161452f565b90965094506040880135915080821115614e1b57600080fd5b50614e288882890161452f565b969995985093965092949392505050565b600080600080600080600060e0888a031215614e5457600080fd5b8735965060208801356001600160401b0380821115614e7257600080fd5b614e7e8b838c01613e5b565b975060408a0135915080821115614e9457600080fd5b614ea08b838c01613ec3565b965060608a0135915080821115614eb657600080fd5b614ec28b838c01613f22565b955060808a0135915080821115614ed857600080fd5b614ee48b838c01613f22565b945060a08a0135915080821115614efa57600080fd5b614f068b838c01613cf5565b935060c08a0135915080821115614f1c57600080fd5b50614f298a828b01613cf5565b91505092959891949750929550565b60008060408385031215614f4b57600080fd5b823591506020830135614f5d81613d64565b809150509250929050565b602081528151602082015260006020830151614f8f60408401826001600160a01b03169052565b506040830151606083015260608301516080830152608083015160a083015260a083015160c083015260c083015160e083015260e08301516101008181850152808501519150506101208181850152808501519150506101408181850152808501519150506101606150048185018315159052565b84015190506101806150198482018315159052565b84015190506101a061502e8482018315159052565b8401516101c0848101919091528401516101e08085019190915284015161026061020080860182905291925090615069610280860184614254565b9086015161022086810191909152860151610240808701919091529095015115159301929092525090919050565b805161416f81613d64565b805161416f81614bf8565b60006101e082840312156150c057600080fd5b6150c8613c5c565b825181526150d860208401615097565b602082015260408301516040820152606083015160608201526080830151608082015260a083015160a082015260c083015160c082015260e083015160e082015261010080840151818301525061012080840151818301525061014061513f8185016150a2565b908201526101606151518482016150a2565b908201526101806151638482016150a2565b908201526101a083810151908201526101c0928301519281019290925250919050565b60006020828403121561519857600080fd5b610df182614ae0565b6000602082840312156151b357600080fd5b610df18261415b565b6000602082840312156151ce57600080fd5b5051919050565b6000602082840312156151e757600080fd5b8151600b8110611d1957600080fd5b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b8381526040602082015260006152396040830184866151f6565b95945050505050565b81835260006001600160fb1b0383111561525b57600080fd5b8260051b80836020870137939093016020019392505050565b838152604060208201526000615239604083018486615242565b87815286602082015260e0604082015260006152ad60e0830188614254565b82810360608401526152bf8188614299565b905082810360808401526152d3818761431a565b905082810360a08401526152e7818661431a565b905082810360c08401526152fb81856142ee565b9a9950505050505050505050565b848152606060208201526000615323606083018587615242565b905060018060a01b038316604083015295945050505050565b87815260806020820152600061535660808301888a615242565b8281036040840152615369818789615242565b905082810360608401526152fb8185876151f6565b86815285602082015260ff8516604082015260a0606082015260006153a760a0830185876151f6565b905063ffffffff83166080830152979650505050505050565b600082825180855260208086019550808260051b84010181860160005b8481101561436757601f19868403018952815160608151818652615403828701826142ee565b838801516001600160a01b0316878901526040938401519390960192909252505097830197908301906001016153dd565b60008282518085526020808601955060208260051b8401016020860160005b8481101561436757601f1986840301895261546f8383516142ee565b98840198925090830190600101615453565b8051608080845281519084018190526000916020919082019060a0860190845b818110156154c65783516001600160a01b0316835292840192918401916001016154a1565b50506020850151925085810360208701526154e18184614299565b92505050604083015184820360408601526154fc8282615434565b915050606083015184820360608601526152398282615434565b85815260a06020820152600061552f60a08301876153c0565b82810360408401526155418187615481565b9050828103606084015261555581866142ee565b91505063ffffffff831660808301529695505050505050565b6000806040838503121561558157600080fd5b825161558c81613d64565b6020840151909250614f5d81613d64565b85815284602082015260ff84166040820152608060608201526000610f1c6080830184866151f6565b86815285602082015260c0604082015260006155e560c08301876153c0565b82810360608401526155f78187615481565b9050828103608084015261560b81866142ee565b905082810360a084015261561f81856142ee565b9998505050505050505050565b8381526020808201849052825161ffff9081166040808501919091529184015116606083015282015163ffffffff16608082015260a081016123a1565b634e487b7160e01b600052603260045260246000fd5b86815285602082015260806040820152600061569f6080830186886151f6565b828103606084015261561f8185876151f6565b60006101008a83528960208401528060408401526156d28184018a614254565b905082810360608401526156e68189614299565b905082810360808401526156fa818861431a565b905082810360a084015261570e818761431a565b905082810360c084015261572281866142ee565b905082810360e084015261573681856142ee565b9b9a5050505050505050505050565b600082601f83011261575657600080fd5b81516020615766613d9a83613cd2565b8083825260208201915060208460051b87010193508684111561578857600080fd5b602086015b84811015613e505780516157a081613d64565b835291830191830161578d565b6000602082840312156157bf57600080fd5b81516001600160401b03808211156157d657600080fd5b9083019061026082860312156157eb57600080fd5b6157f3613c7f565b8251815261580360208401615097565b602082015260408301516040820152606083015160608201526080830151608082015260a083015160a082015260c083015160c082015260e083015160e082015261010080840151818301525061012080840151818301525061014061586a8185016150a2565b9082015261016061587c8482016150a2565b9082015261018061588e8482016150a2565b908201526101a083810151908201526101c080840151908201526101e080840151838111156158bc57600080fd5b6158c888828701615745565b91830191909152506102008381015190820152610220808401519082015261024091506158f68284016150a2565b91810191909152949350505050565b600082516159178184602087016142ca565b9190910192915050565b634e487b7160e01b600052601160045260246000fd5b81810381811115610df457610df4615921565b60006020828403121561595c57600080fd5b81516001600160601b0381168114611d1957600080fd5b80820180821115610df457610df4615921565b600181811c9082168061599a57607f821691505b6020821081036159ba57634e487b7160e01b600052602260045260246000fd5b50919050565b6000826159dd57634e487b7160e01b600052601260045260246000fd5b500490565b8082028115828204841417610df457610df4615921565b600060018201615a0b57615a0b615921565b5060010190565b602081526000610df160208301846142ee565b63ffffffff8a1681526001600160a01b038916602082015261012060408201819052600090615a568382018b614254565b90508281036060840152615a6a818a614299565b90508281036080840152615a7e818961431a565b905082810360a0840152615a92818861431a565b90508560c08401528460e0840152828103610100840152615ab381856142ee565b9c9b505050505050505050505050565b63ffffffff8616815260a060208201526000615ae260a0830187614254565b6001600160401b0395909516604083015250606081019290925260809091015292915050565b601f821115613305576000816000526020600020601f850160051c81016020861015615b315750805b601f850160051c820191505b818110156116ea57828155600101615b3d565b81516001600160401b03811115615b6957615b69613c1e565b615b7d81615b778454615986565b84615b08565b602080601f831160018114615bb25760008415615b9a5750858301515b600019600386901b1c1916600185901b1785556116ea565b600085815260208120601f198616915b82811015615be157888601518255948401946001909101908401615bc2565b5085821015615bff5787850151600019600388901b60f8161c191681555b5050505050600190811b0190555056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c65644e6f756e7344414f3a3a67657444796e616d696351756f72756d506172616d7341743a20626c6f636b206e756d62657220657863656564732033322062697473a26469706673582212209727ca74986184ed031177b5021a46512e6f96c4c604da0c453d87c2106b183b64736f6c63430008170033", + "nonce": "0x145", + "chainId": "0xaa36a7", + "accessList": null, + "type": null + }, + "additionalContracts": [], + "isFixedGasLimit": false + } + ], + "receipts": [ + { + "status": "0x1", + "cumulativeGasUsed": "0xf8e65e", + "logs": [], + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "type": "0x2", + "transactionHash": "0x992ca4f70c62a5af2707e4187f7873a56f96ad58827c7e695370cd0bbb18411c", + "transactionIndex": "0x51", + "blockHash": "0x89d5d78ed4b0195d325d38c86e54056938847609489e1c0c2ef5756242a80e07", + "blockNumber": "0x57e113", + "gasUsed": "0x1e623e", + "effectiveGasPrice": "0xee7dafe", + "from": "0xad36c32f3c28a9214adcf50a09998de1d3b0ee06", + "to": null, + "contractAddress": "0x02e813dbeaddefe9921f4a2093206aefef4453d6" + }, + { + "status": "0x1", + "cumulativeGasUsed": "0xfbcd95", + "logs": [], + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "type": "0x2", + "transactionHash": "0x6365742b0e5dba31c0c11d73a1998fc4c5fe197a57f2c1e27cec0bea4f285184", + "transactionIndex": "0x52", + "blockHash": "0x89d5d78ed4b0195d325d38c86e54056938847609489e1c0c2ef5756242a80e07", + "blockNumber": "0x57e113", + "gasUsed": "0x2e737", + "effectiveGasPrice": "0xee7dafe", + "from": "0xad36c32f3c28a9214adcf50a09998de1d3b0ee06", + "to": null, + "contractAddress": "0x970583ad744c3f73eafc7f25591373ba17bdd286" + }, + { + "status": "0x1", + "cumulativeGasUsed": "0x10cb84e", + "logs": [], + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "type": "0x2", + "transactionHash": "0xc0328521eb096b2b664efd70f89a555d94c03a0ec48c29bcdd4b16b31a4d1135", + "transactionIndex": "0x53", + "blockHash": "0x89d5d78ed4b0195d325d38c86e54056938847609489e1c0c2ef5756242a80e07", + "blockNumber": "0x57e113", + "gasUsed": "0x10eab9", + "effectiveGasPrice": "0xee7dafe", + "from": "0xad36c32f3c28a9214adcf50a09998de1d3b0ee06", + "to": null, + "contractAddress": "0x3f08ce1a659c34737d1a1aae437bf5a99a1857be" + }, + { + "status": "0x1", + "cumulativeGasUsed": "0x14a4293", + "logs": [], + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "type": "0x2", + "transactionHash": "0xacd69dc1124b78c0e1941053a221a43cd0c3751eada70aee92fa8cac7e79963b", + "transactionIndex": "0x54", + "blockHash": "0x89d5d78ed4b0195d325d38c86e54056938847609489e1c0c2ef5756242a80e07", + "blockNumber": "0x57e113", + "gasUsed": "0x3d8a45", + "effectiveGasPrice": "0xee7dafe", + "from": "0xad36c32f3c28a9214adcf50a09998de1d3b0ee06", + "to": null, + "contractAddress": "0x81ede38efc867818bf77978514f5dca76c20a050" + }, + { + "status": "0x1", + "cumulativeGasUsed": "0x1612ced", + "logs": [], + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "type": "0x2", + "transactionHash": "0xd8e5ad5005fa8e231687ee17d418d98e0bf39f486d83f80aec0d71fdff72999a", + "transactionIndex": "0x55", + "blockHash": "0x89d5d78ed4b0195d325d38c86e54056938847609489e1c0c2ef5756242a80e07", + "blockNumber": "0x57e113", + "gasUsed": "0x16ea5a", + "effectiveGasPrice": "0xee7dafe", + "from": "0xad36c32f3c28a9214adcf50a09998de1d3b0ee06", + "to": null, + "contractAddress": "0x30656985039923eaa1ebb968fe84a1277581f602" + }, + { + "status": "0x1", + "cumulativeGasUsed": "0x1b02ab9", + "logs": [], + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "type": "0x2", + "transactionHash": "0xd534b73edd763c42dd5102fb7ec5b3c7b45936edc12dde860bdd8b5c87cb257a", + "transactionIndex": "0x56", + "blockHash": "0x89d5d78ed4b0195d325d38c86e54056938847609489e1c0c2ef5756242a80e07", + "blockNumber": "0x57e113", + "gasUsed": "0x4efdcc", + "effectiveGasPrice": "0xee7dafe", + "from": "0xad36c32f3c28a9214adcf50a09998de1d3b0ee06", + "to": null, + "contractAddress": "0x017b4fd1a03308df03cb9a03a303fe9e6bc8ab7d" + } + ], + "libraries": [ + "contracts/governance/NounsDAOAdmin.sol:NounsDAOAdmin:0x02e813dbeaDDEFE9921f4a2093206AefeF4453d6", + "contracts/governance/NounsDAODynamicQuorum.sol:NounsDAODynamicQuorum:0x970583ad744c3F73EAfc7f25591373bA17BDD286", + "contracts/governance/NounsDAOProposals.sol:NounsDAOProposals:0x81EDe38Efc867818BF77978514f5dCa76C20A050", + "contracts/governance/NounsDAOVotes.sol:NounsDAOVotes:0x30656985039923EAa1eBb968fe84A1277581f602", + "contracts/governance/fork/NounsDAOFork.sol:NounsDAOFork:0x3F08ce1a659c34737D1a1aae437bF5A99A1857be" + ], + "pending": [], + "returns": { + "daoLogic": { + "internal_type": "contract NounsDAOLogicV4", + "value": "0x017B4Fd1a03308Df03CB9a03A303FE9E6bC8aB7d" + } + }, + "timestamp": 1713864124, + "chain": 11155111, + "commit": "82b8d911" +} \ No newline at end of file diff --git a/packages/nouns-contracts/broadcast/DeployRewardsSepolia.s.sol/11155111/run-latest.json b/packages/nouns-contracts/broadcast/DeployRewardsSepolia.s.sol/11155111/run-latest.json new file mode 100644 index 0000000000..d4bcf4a54d --- /dev/null +++ b/packages/nouns-contracts/broadcast/DeployRewardsSepolia.s.sol/11155111/run-latest.json @@ -0,0 +1,159 @@ +{ + "transactions": [ + { + "hash": "0x5b7d177cab55f11783b5bb8b8147c40a241ec93da31e46bc3ec4db3604154ab8", + "transactionType": "CREATE", + "contractName": "NounsClientTokenDescriptor", + "contractAddress": "0xD24ee92FBb1F75c2e90B3560CAd09C11A31d39A4", + "function": null, + "arguments": null, + "transaction": { + "type": "0x02", + "from": "0xad36c32f3c28a9214adcf50a09998de1d3b0ee06", + "gas": "0x1ada49", + "value": "0x0", + "data": "0x608060405234801561001057600080fd5b50611784806100206000396000f3fe608060405234801561001057600080fd5b506004361061002b5760003560e01c80635fa2601514610030575b600080fd5b61004361003e3660046104fb565b610059565b6040516100509190610600565b60405180910390f35b606060006100668461013b565b836080015160405160200161007c92919061064f565b60408051601f1981840301815260c0830190915260928083529092506000916100f39161169d60208301396100b18787610244565b604051806107a001604052806107658152602001610ed861076591396040516020016100df939291906106a5565b604051602081830303815290604052610282565b9050610111828560a00151836040516020016100df939291906106e8565b60405160200161012191906107af565b604051602081830303815290604052925050505b92915050565b6060816000036101625750506040805180820190915260018152600360fc1b602082015290565b8160005b811561018c57806101768161080a565b91506101859050600a83610839565b9150610166565b60008167ffffffffffffffff8111156101a7576101a76103e7565b6040519080825280601f01601f1916602001820160405280156101d1576020820181803683370190505b5090505b841561023c576101e660018361084d565b91506101f3600a86610860565b6101fe906030610874565b60f81b81838151811061021357610213610887565b60200101906001600160f81b031916908160001a905350610235600a86610839565b94506101d5565b949350505050565b60608160a001516102548461013b565b836080015160405160200161026b9392919061089d565b604051602081830303815290604052905092915050565b606081516000036102a157505060408051602081019091526000815290565b600060405180606001604052806040815260200161163d60409139905060006003845160026102d09190610874565b6102da9190610839565b6102e5906004610e80565b905060006102f4826020610874565b67ffffffffffffffff81111561030c5761030c6103e7565b6040519080825280601f01601f191660200182016040528015610336576020820181803683370190505b509050818152600183018586518101602084015b818310156103a2576003830192508251603f8160121c168501518253600182019150603f81600c1c168501518253600182019150603f8160061c168501518253600182019150603f811685015182535060010161034a565b6003895106600181146103bc57600281146103cd576103d9565b613d3d60f01b6001198301526103d9565b603d60f81b6000198301525b509398975050505050505050565b634e487b7160e01b600052604160045260246000fd5b60405160c0810167ffffffffffffffff81118282101715610420576104206103e7565b60405290565b8035801515811461043657600080fd5b919050565b80356bffffffffffffffffffffffff8116811461043657600080fd5b803566ffffffffffffff8116811461043657600080fd5b600082601f83011261047f57600080fd5b813567ffffffffffffffff8082111561049a5761049a6103e7565b604051601f8301601f19908116603f011681019082821181831017156104c2576104c26103e7565b816040528381528660208588010111156104db57600080fd5b836020870160208301376000602085830101528094505050505092915050565b6000806040838503121561050e57600080fd5b82359150602083013567ffffffffffffffff8082111561052d57600080fd5b9084019060c0828703121561054157600080fd5b6105496103fd565b61055283610426565b81526105606020840161043b565b60208201526105716040840161043b565b604082015261058260608401610457565b606082015260808301358281111561059957600080fd5b6105a58882860161046e565b60808301525060a0830135828111156105bd57600080fd5b6105c98882860161046e565b60a0830152508093505050509250929050565b60005b838110156105f75781810151838201526020016105df565b50506000910152565b602081526000825180602084015261061f8160408501602087016105dc565b601f01601f19169190910160400192915050565b600081516106458185602086016105dc565b9290920192915050565b6c02737bab7399021b634b2b73a1609d1b81526000835161067781600d8501602088016105dc565b6101d160f51b600d91840191820152835161069981600f8401602088016105dc565b01600f01949350505050565b600084516106b78184602089016105dc565b8451908301906106cb8183602089016105dc565b84519101906106de8183602088016105dc565b0195945050505050565b683d913730b6b2911d1160b91b8152835160009061070d8160098501602089016105dc565b71111610113232b9b1b934b83a34b7b7111d1160711b600991840191820152845161073f81601b8401602089016105dc565b6c1116101134b6b0b3b2911d101160991b601b92909101918201527f646174613a696d6167652f7376672b786d6c3b6261736536342c000000000000602882015283516107938160428401602088016105dc565b61227d60f01b6042929091019182015260440195945050505050565b7f646174613a6170706c69636174696f6e2f6a736f6e3b6261736536342c0000008152600082516107e781601d8501602087016105dc565b91909101601d0192915050565b634e487b7160e01b600052601160045260246000fd5b60006001820161081c5761081c6107f4565b5060010190565b634e487b7160e01b600052601260045260246000fd5b60008261084857610848610823565b500490565b81810381811115610135576101356107f4565b60008261086f5761086f610823565b500690565b80820180821115610135576101356107f4565b634e487b7160e01b600052603260045260246000fd5b600080516020610eb8833981519152815260008051602061172f8339815191526020820152600080516020610e9883398151915260408201527f73697a653d2232302220666f6e742d7765696768743d22626f6c6422206c6574606082015260008051602061167d83398151915260808201527f793d223136352e383232223e5645524946494544204e4f554e5320434c49454e60a08201526f2a1e17ba39b830b71f1e17ba32bc3a1f60811b60c08201527f3c746578742066696c6c3d22626c61636b222066696c6c2d6f7061636974793d60d08201527f22302e352220786d6c3a73706163653d22707265736572766522207374796c6560f08201527f3d2277686974652d73706163653a207072652220666f6e742d66616d696c793d6101108201527f22436f7572696572204e65772220666f6e742d73697a653d2231352220666f6e6101308201527f742d7765696768743d22626f6c6422206c65747465722d73706163696e673d226101508201527f30656d223e3c747370616e20783d2233302220793d223334362e343932223e436101708201527f6c69656e742055524c3a3c2f747370616e3e3c2f746578743e000000000000006101908201526000610e77610b1a610e71610de3610cd6610b1a610cd0610c42610b35610b1a610b146101a98d01600080516020610eb8833981519152815260008051602061172f8339815191526020820152600080516020610e9883398151915260408201527f73697a653d2231352220666f6e742d7765696768743d22626f6c6422206c6574606082015260008051602061167d83398151915260808201526b3c9e91199b1a971a1c99111f60a11b60a082015260ac0190565b8f610633565b6e1e17ba39b830b71f1e17ba32bc3a1f60891b8152600f0190565b7f3c746578742066696c6c3d22626c61636b222066696c6c2d6f7061636974793d81527f22302e352220786d6c3a73706163653d22707265736572766522207374796c6560208201527f3d2277686974652d73706163653a207072652220666f6e742d66616d696c793d60408201527f22436f7572696572204e65772220666f6e742d73697a653d2231352220666f6e60608201527f742d7765696768743d22626f6c6422206c65747465722d73706163696e673d2260808201527f30656d223e3c747370616e20783d2233302220793d223239352e343932223e4360a08201527f6c69656e742049443a3c2f747370616e3e3c2f746578743e000000000000000060c082015260d80190565b600080516020610eb8833981519152815260008051602061172f8339815191526020820152600080516020610e9883398151915260408201527f73697a653d2231352220666f6e742d7765696768743d22626f6c6422206c6574606082015260008051602061167d83398151915260808201526b3c9e9119989a171a1c99111f60a11b60a082015260ac0190565b8a610633565b7f3c746578742066696c6c3d22626c61636b222066696c6c2d6f7061636974793d81527f22302e352220786d6c3a73706163653d22707265736572766522207374796c6560208201527f3d2277686974652d73706163653a207072652220666f6e742d66616d696c793d60408201527f22436f7572696572204e65772220666f6e742d73697a653d2231352220666f6e60608201527f742d7765696768743d22626f6c6422206c65747465722d73706163696e673d2260808201527f30656d223e3c747370616e20783d2233302220793d223234342e343932223e4360a08201527f6c69656e74204e616d653a3c2f747370616e3e3c2f746578743e00000000000060c082015260da0190565b600080516020610eb8833981519152815260008051602061172f8339815191526020820152600080516020610e9883398151915260408201527f73697a653d2231352220666f6e742d7765696768743d22626f6c6422206c6574606082015260008051602061167d83398151915260808201526b3c9e91191b19971a1c99111f60a11b60a082015260ac0190565b85610633565b95945050505050565b8082028115828204841417610135576101356107f456fe20666f6e742d66616d696c793d22436f7572696572204e65772220666f6e742d3c746578742066696c6c3d22626c61636b2220786d6c3a73706163653d2270723c7061746820643d224d37352031303448343556313039483735563130345a222066696c6c3d2223443139413534222f3e3c7061746820643d224d313130203130344838305631303948313130563130345a222066696c6c3d2223443139413534222f3e3c7061746820643d224d35302031303948343556313134483530563130395a222066696c6c3d2223443139413534222f3e3c7061746820643d224d36302031303948353056313134483630563130395a222066696c6c3d227768697465222f3e3c7061746820643d224d37302031303948363056313134483730563130395a222066696c6c3d22626c61636b222f3e3c7061746820643d224d37352031303948373056313134483735563130395a222066696c6c3d2223443139413534222f3e3c7061746820643d224d38352031303948383056313134483835563130395a222066696c6c3d2223443139413534222f3e3c7061746820643d224d39352031303948383556313134483935563130395a222066696c6c3d227768697465222f3e3c7061746820643d224d313035203130394839355631313448313035563130395a222066696c6c3d22626c61636b222f3e3c7061746820643d224d31313020313039483130355631313448313130563130395a222066696c6c3d2223443139413534222f3e3c7061746820643d224d35302031313448333056313139483530563131345a222066696c6c3d2223443139413534222f3e3c7061746820643d224d36302031313448353056313139483630563131345a222066696c6c3d227768697465222f3e3c7061746820643d224d37302031313448363056313139483730563131345a222066696c6c3d22626c61636b222f3e3c7061746820643d224d38352031313448373056313139483835563131345a222066696c6c3d2223443139413534222f3e3c7061746820643d224d39352031313448383556313139483935563131345a222066696c6c3d227768697465222f3e3c7061746820643d224d313035203131344839355631313948313035563131345a222066696c6c3d22626c61636b222f3e3c7061746820643d224d31313020313134483130355631313948313130563131345a222066696c6c3d2223443139413534222f3e3c7061746820643d224d33352031313948333056313234483335563131395a222066696c6c3d2223443139413534222f3e3c7061746820643d224d35302031313948343556313234483530563131395a222066696c6c3d2223443139413534222f3e3c7061746820643d224d36302031313948353056313234483630563131395a222066696c6c3d227768697465222f3e3c7061746820643d224d37302031313948363056313234483730563131395a222066696c6c3d22626c61636b222f3e3c7061746820643d224d37352031313948373056313234483735563131395a222066696c6c3d2223443139413534222f3e3c7061746820643d224d38352031313948383056313234483835563131395a222066696c6c3d2223443139413534222f3e3c7061746820643d224d39352031313948383556313234483935563131395a222066696c6c3d227768697465222f3e3c7061746820643d224d313035203131394839355631323448313035563131395a222066696c6c3d22626c61636b222f3e3c7061746820643d224d31313020313139483130355631323448313130563131395a222066696c6c3d2223443139413534222f3e3c7061746820643d224d33352031323448333056313239483335563132345a222066696c6c3d2223443139413534222f3e3c7061746820643d224d35302031323448343556313239483530563132345a222066696c6c3d2223443139413534222f3e3c7061746820643d224d36302031323448353056313239483630563132345a222066696c6c3d227768697465222f3e3c7061746820643d224d37302031323448363056313239483730563132345a222066696c6c3d22626c61636b222f3e3c7061746820643d224d37352031323448373056313239483735563132345a222066696c6c3d2223443139413534222f3e3c7061746820643d224d38352031323448383056313239483835563132345a222066696c6c3d2223443139413534222f3e3c7061746820643d224d39352031323448383556313239483935563132345a222066696c6c3d227768697465222f3e3c7061746820643d224d313035203132344839355631323948313035563132345a222066696c6c3d22626c61636b222f3e3c7061746820643d224d31313020313234483130355631323948313130563132345a222066696c6c3d2223443139413534222f3e3c7061746820643d224d37352031323948343556313334483735563132395a222066696c6c3d2223443139413534222f3e3c7061746820643d224d313130203132394838305631333448313130563132395a222066696c6c3d2223443139413534222f3e3c6c696e652078313d223330222079313d223230312e35222078323d22333730222079323d223230312e3522207374726f6b653d22626c61636b22207374726f6b652d6f7061636974793d22302e35222f3e3c2f7376673e4142434445464748494a4b4c4d4e4f505152535455565758595a6162636465666768696a6b6c6d6e6f707172737475767778797a303132333435363738392b2f7465722d73706163696e673d2230656d223e3c747370616e20783d22333022203c7376672077696474683d2234303022206865696768743d22343030222076696577426f783d223020302034303020343030222066696c6c3d226e6f6e652220786d6c6e733d22687474703a2f2f7777772e77332e6f72672f323030302f737667223e3c726563742077696474683d2234303022206865696768743d22343030222066696c6c3d2223443544374531222f3e65736572766522207374796c653d2277686974652d73706163653a2070726522a26469706673582212206f0e8f2189131bb3093dc5ae40fa1a927c5a91d95f662879a8db94b72bf572bd64736f6c63430008170033", + "nonce": "0x135", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0xbc12392548073ee814ef23662978de7fdc3df93d190a33f96acee824e202c917", + "transactionType": "CREATE", + "contractName": "Rewards", + "contractAddress": "0x16029071Fab212E7dD59DC76f65Fac398C49Cc13", + "function": null, + "arguments": [ + "0xDefBf39D0E251fc058fF44B96D40Cf3347596EB9", + "0xf459b7573a9c2B37eF21F2f7a1a96339E343CdD8" + ], + "transaction": { + "type": "0x02", + "from": "0xad36c32f3c28a9214adcf50a09998de1d3b0ee06", + "gas": "0x6835a0", + "value": "0x0", + "data": "0x60e0604052306080523480156200001557600080fd5b5060405162005f6638038062005f66833981016040819052620000389162000129565b600054610100900460ff168062000052575060005460ff16155b620000ba5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b606482015260840160405180910390fd5b600054610100900460ff16158015620000dd576000805461ffff19166101011790555b6001600160a01b0380841660a052821660c052801562000103576000805461ff00191690555b50505062000161565b80516001600160a01b03811681146200012457600080fd5b919050565b600080604083850312156200013d57600080fd5b62000148836200010c565b915062000158602084016200010c565b90509250929050565b60805160a05160c051615d9d620001c96000396000818161091d01528181610b3101526116d60152600081816104cc015281816111e3015281816126a2015261285701526000818161105b0152818161109b01528181611a4a0152611a8a0152615d9d6000f3fe6080604052600436106102ae5760003560e01c80635e615a6b11610175578063a22cb465116100dc578063c87b56dd11610095578063e985e9c51161006f578063e985e9c5146108eb578063ed9152c81461090b578063f2fde38b1461093f578063f851a4401461095f57600080fd5b8063c87b56dd14610896578063cc9df021146108b6578063d715d101146108d657600080fd5b8063a22cb465146107be578063a2d8437b146107de578063ac4951f6146107fe578063b289a2bb1461081e578063b88d4fde14610856578063becbeb221461087657600080fd5b806375794a3c1161012e57806375794a3c1461072c5780637bf1a627146107415780637d15f041146107565780638456cb59146107765780638da5cb5b1461078b57806395d89b41146107a957600080fd5b80635e615a6b146106055780635f27663b1461068a5780636352211e146106b7578063704b6c02146106d757806370a08231146106f7578063715018a61461071757600080fd5b8063303e74df1161021957806342842e0e116101d257806342842e0e146105655780634364d973146105855780634818ac42146105a55780634f1ef286146105c557806354b1faeb146105d85780635c975abb146105ed57600080fd5b8063303e74df146104a5578063337344a2146104ba5780633659cfe6146104ee5780633b5003c01461050e5780633f4ba83a1461053b5780633fabc2521461055057600080fd5b8063095ea7b31161026b578063095ea7b3146103b95780630ba28a64146103d95780631ac8875d146103f957806320e476411461043b57806323b872dd1461045b5780632a7273111461047b57600080fd5b806301b9a397146102b357806301e33667146102d557806301ffc9a7146102f557806306fdde031461032a57806307d7461e1461034c578063081812fc14610381575b600080fd5b3480156102bf57600080fd5b506102d36102ce366004614824565b610974565b005b3480156102e157600080fd5b506102d36102f0366004614841565b6109d6565b34801561030157600080fd5b50610315610310366004614898565b610a19565b60405190151581526020015b60405180910390f35b34801561033657600080fd5b5061033f610a6b565b6040516103219190614905565b34801561035857600080fd5b5061036c610367366004614918565b610afe565b60408051928352602083019190915201610321565b34801561038d57600080fd5b506103a161039c36600461493a565b610be2565b6040516001600160a01b039091168152602001610321565b3480156103c557600080fd5b506102d36103d4366004614953565b610c79565b3480156103e557600080fd5b506102d36103f436600461497f565b610d89565b34801561040557600080fd5b5061042d7f9a06af3161ac5b0c3de4e6c981ab9d9f60b530386f5eaae00d541393fbecd70081565b604051908152602001610321565b34801561044757600080fd5b506102d36104563660046149a3565b610dd4565b34801561046757600080fd5b506102d3610476366004614841565b610fe3565b34801561048757600080fd5b50610490611014565b60405163ffffffff9091168152602001610321565b3480156104b157600080fd5b506103a1611033565b3480156104c657600080fd5b506103a17f000000000000000000000000000000000000000000000000000000000000000081565b3480156104fa57600080fd5b506102d3610509366004614824565b611051565b34801561051a57600080fd5b5061052e6105293660046149fa565b611119565b6040516103219190614a59565b34801561054757600080fd5b506102d3611430565b34801561055c57600080fd5b5061042d6114b6565b34801561057157600080fd5b506102d3610580366004614841565b6114d6565b34801561059157600080fd5b506104906105a0366004614ab4565b6114f1565b3480156105b157600080fd5b506102d36105c03660046149fa565b6115e5565b6102d36105d3366004614c71565b611a40565b3480156105e457600080fd5b5061042d611af9565b3480156105f957600080fd5b5060975460ff16610315565b34801561061157600080fd5b5061061a611b18565b6040516103219190600060e08201905063ffffffff835116825260ff6020840151166020830152604083015161ffff80821660408501528060608601511660608501528060808601511660808501528060a08601511660a0850152505060ff60c08401511660c083015292915050565b34801561069657600080fd5b506106aa6106a53660046149fa565b611bd6565b6040516103219190614cc0565b3480156106c357600080fd5b506103a16106d236600461493a565b611db1565b3480156106e357600080fd5b506102d36106f2366004614824565b611e29565b34801561070357600080fd5b5061042d610712366004614824565b611e82565b34801561072357600080fd5b506102d3611f0a565b34801561073857600080fd5b50610490611f40565b34801561074d57600080fd5b506103a1611f58565b34801561076257600080fd5b506102d3610771366004614824565b611f76565b34801561078257600080fd5b506102d3611fcf565b34801561079757600080fd5b5060c9546001600160a01b03166103a1565b3480156107b557600080fd5b5061033f612055565b3480156107ca57600080fd5b506102d36107d9366004614d49565b612065565b3480156107ea57600080fd5b506102d36107f9366004614db7565b612070565b34801561080a57600080fd5b506102d3610819366004614eec565b61236a565b34801561082a57600080fd5b5061083e6108393660046149fa565b612408565b6040516001600160601b039091168152602001610321565b34801561086257600080fd5b506102d3610871366004614f0a565b612451565b34801561088257600080fd5b506102d3610891366004614f75565b612483565b3480156108a257600080fd5b5061033f6108b136600461493a565b612579565b3480156108c257600080fd5b506102d36108d1366004614ff7565b61261f565b3480156108e257600080fd5b5061042d613245565b3480156108f757600080fd5b5061031561090636600461507e565b613265565b34801561091757600080fd5b506103a17f000000000000000000000000000000000000000000000000000000000000000081565b34801561094b57600080fd5b506102d361095a366004614824565b613294565b34801561096b57600080fd5b506103a161332c565b60c9546001600160a01b031633146109a75760405162461bcd60e51b815260040161099e906150ac565b60405180910390fd5b60006109b161334a565b60050180546001600160a01b0319166001600160a01b03939093169290921790915550565b60c9546001600160a01b03163314610a005760405162461bcd60e51b815260040161099e906150ac565b610a146001600160a01b038416838361336e565b505050565b60006001600160e01b031982166380ac58cd60e01b1480610a4a57506001600160e01b03198216635b5e139f60e01b145b80610a6557506301ffc9a760e01b6001600160e01b03198316145b92915050565b606061012d8054610a7b906150e1565b80601f0160208091040260200160405190810160405280929190818152602001828054610aa7906150e1565b8015610af45780601f10610ac957610100808354040283529160200191610af4565b820191906000526020600020905b815481529060010190602001808311610ad757829003601f168201915b5050505050905090565b6040516309b8570960e01b8152600481018390526024810182905260016044820152600090819081906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906309b8570990606401600060405180830381865afa158015610b78573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610ba09190810190615143565b9050610bab816133c0565b92508060018251610bbc9190615245565b81518110610bcc57610bcc615258565b6020026020010151606001519150509250929050565b600081815261012f60205260408120546001600160a01b0316610c5c5760405162461bcd60e51b815260206004820152602c60248201527f4552433732313a20617070726f76656420717565727920666f72206e6f6e657860448201526b34b9ba32b73a103a37b5b2b760a11b606482015260840161099e565b50600090815261013160205260409020546001600160a01b031690565b6000610c8482611db1565b9050806001600160a01b0316836001600160a01b031603610cf15760405162461bcd60e51b815260206004820152602160248201527f4552433732313a20617070726f76616c20746f2063757272656e74206f776e656044820152603960f91b606482015260840161099e565b336001600160a01b0382161480610d0d5750610d0d8133613265565b610d7f5760405162461bcd60e51b815260206004820152603860248201527f4552433732313a20617070726f76652063616c6c6572206973206e6f74206f7760448201527f6e6572206e6f7220617070726f76656420666f7220616c6c0000000000000000606482015260840161099e565b610a148383613406565b60c9546001600160a01b03163314610db35760405162461bcd60e51b815260040161099e906150ac565b6000610dbd61334a565b90508160018201610dce8282615288565b50505050565b60975460ff1615610df75760405162461bcd60e51b815260040161099e906153cb565b6000610e0161334a565b63ffffffff8516600081815260048301602052604090209192503390610e2690611db1565b6001600160a01b031614610e7c5760405162461bcd60e51b815260206004820152601860248201527f6d75737420626520636c69656e74204e4654206f776e65720000000000000000604482015260640161099e565b805460ff16610ec35760405162461bcd60e51b815260206004820152601360248201527218db1a595b9d081b9bdd08185c1c1c9bdd9959606a1b604482015260640161099e565b80546001600160601b03600160681b8204811691610ee89183916101009004166153f5565b6001600160601b0316846001600160601b03161115610f3c5760405162461bcd60e51b815260206004820152601060248201526f616d6f756e7420746f6f206c6172676560801b604482015260640161099e565b610f46848261541c565b82546bffffffffffffffffffffffff60681b1916600160681b6001600160601b03928316021783556040805191861682526001600160a01b038716602083015263ffffffff8816917f1812827f1c6a24a5651bf4de08620620edf7827369871a784625bf0ad118f120910160405180910390a26002830154610fdb906001600160a01b0316866001600160601b03871661336e565b505050505050565b610fed3382613475565b6110095760405162461bcd60e51b815260040161099e9061543c565b610a14838383613545565b60008061101f61334a565b54600160401b900463ffffffff1692915050565b60008061103e61334a565b600501546001600160a01b031692915050565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001630036110995760405162461bcd60e51b815260040161099e9061548d565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166110cb6136e8565b6001600160a01b0316146110f15760405162461bcd60e51b815260040161099e906154d9565b6110fa81613716565b6040805160008082526020820190925261111691839190613740565b50565b6060600061112561334a565b90506000611131611f40565b63ffffffff1690506000816001600160401b0381111561115357611153614b1f565b60405190808252806020026020018201604052801561117c578160200160208202803683370190505b50905060005b828163ffffffff1610156111ce5780828263ffffffff16815181106111a9576111a9615258565b63ffffffff909216602092830291909101909101526111c781615525565b9050611182565b5082546040516337e06f7160e11b81526000917f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031691636fc0dee29161123191600160401b90910463ffffffff16908a908790600401615548565b600060405180830381865afa15801561124e573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611276919081019061560d565b90506000836001600160401b0381111561129257611292614b1f565b6040519080825280602002602001820160405280156112bb578160200160208202803683370190505b50905060005b82518110156113515760005b85811015611348578382815181106112e7576112e7615258565b60200260200101516101000151818151811061130557611305615258565b60200260200101516000015183828151811061132357611323615258565b602002602001018181516113379190615752565b63ffffffff169052506001016112cd565b506001016112c1565b50600080856001600160401b0381111561136d5761136d614b1f565b604051908082528060200260200182016040528015611396578160200160208202803683370190505b50905060005b868163ffffffff161015611421576000848263ffffffff16815181106113c4576113c4615258565b602002602001015163ffffffff161115611411578082846113e48161576f565b9550815181106113f6576113f6615258565b602002602001019063ffffffff16908163ffffffff16815250505b61141a81615525565b905061139c565b50908152979650505050505050565b600061143a61334a565b60c9549091506001600160a01b0316331480611462575060038101546001600160a01b031633145b6114ae5760405162461bcd60e51b815260206004820152601d60248201527f43616c6c6572206d757374206265206f776e6572206f722061646d696e000000604482015260640161099e565b61111661388b565b6000806114c161334a565b54640100000000900463ffffffff1692915050565b610a1483838360405180602001604052806000815250612451565b60006114ff60975460ff1690565b1561151c5760405162461bcd60e51b815260040161099e906153cb565b600061152661334a565b805490915063ffffffff1661153c816001615752565b825463ffffffff191663ffffffff91821617835561155d903390831661391e565b63ffffffff81166000908152600483016020526040902060018101611583888a836157d0565b50600281016115938688836157d0565b508163ffffffff167f65beab8930287623c694d7e645cdd4b7b83bebaaac913f30933d4c691a271e3c898989896040516115d094939291906158b8565b60405180910390a2509150505b949350505050565b60975460ff16156116085760405162461bcd60e51b815260040161099e906153cb565b60005a9050600061161761334a565b8054600182015491925060009164010000000090910463ffffffff169061164890600160681b900460ff16826158df565b8563ffffffff16101561169d5760405162461bcd60e51b815260206004820152601960248201527f6c6173744e6f756e4964206d7573742062652068696768657200000000000000604482015260640161099e565b6116a8856001615752565b835463ffffffff919091166401000000000267ffffffff000000001990911617835560006001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001663b1296a9483611707896001615752565b6040516001600160e01b031960e085901b168152600481019290925263ffffffff16602482015260016044820152606401600060405180830381865afa158015611755573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261177d9190810190615143565b9050600081600183516117909190615245565b815181106117a0576117a0615258565b602002602001015190508663ffffffff1681606001511480156117cd57506001816000015163ffffffff16115b6118195760405162461bcd60e51b815260206004820152601a60248201527f6c6173744e6f756e4964206d75737420626520736574746c6564000000000000604482015260640161099e565b60006001611825611f40565b61182f91906158f2565b9050600061183c82613a63565b905060005b84518110156118ba57600085828151811061185e5761185e615258565b60200260200101519050806080015163ffffffff1660001415801561189357508363ffffffff16816080015163ffffffff1611155b156118b15760808101516020820151600199506118b1918591613b52565b50600101611841565b506001870154600160581b900461ffff1660006118d683613c51565b905060005b818163ffffffff1610156119d65760006118f58583613c70565b905060006127108561ffff168360200151611910919061590f565b61191a9190615926565b905061192581613cba565b825163ffffffff16600090815260048e0160205260409020805460019061195b90849061010090046001600160601b031661541c565b92506101000a8154816001600160601b0302191690836001600160601b03160217905550816000015163ffffffff167f8a6390ffb12581558b6798514e694cb23b44ff553c82d4e69024ab1fe2230ae2826040516119bb91815260200190565b60405180910390a25050806119cf90615525565b90506118db565b506040805188815263ffffffff8d1660208201527ff48a534da18c3b27deb2da48e4a2d8b1888ad5cb761889d25b692de9da944d22910160405180910390a18715611a33576002890154611a33906001600160a01b03168b613d26565b5050505050505050505050565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163003611a885760405162461bcd60e51b815260040161099e9061548d565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316611aba6136e8565b6001600160a01b031614611ae05760405162461bcd60e51b815260040161099e906154d9565b611ae982613716565b611af582826001613740565b5050565b600080611b0461334a565b54600160601b900463ffffffff1692915050565b6040805160e081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905290611b5961334a565b6040805160e08101825260019092015463ffffffff8116835260ff64010000000082048116602085015261ffff650100000000008304811693850193909352600160381b820483166060850152600160481b820483166080850152600160581b820490921660a0840152600160681b90041660c082015292915050565b6040805160c08101825260008082526020820181905291810182905260608082018390526080820181905260a082015290611c0f61334a565b63ffffffff84166000908152600482016020908152604091829020825160c081018452815460ff81161515825261010081046001600160601b0390811694830194909452600160681b810490931693810193909352600160c81b90910466ffffffffffffff166060830152600181018054939450919290916080840191611c95906150e1565b80601f0160208091040260200160405190810160405280929190818152602001828054611cc1906150e1565b8015611d0e5780601f10611ce357610100808354040283529160200191611d0e565b820191906000526020600020905b815481529060010190602001808311611cf157829003601f168201915b50505050508152602001600282018054611d27906150e1565b80601f0160208091040260200160405190810160405280929190818152602001828054611d53906150e1565b8015611da05780601f10611d7557610100808354040283529160200191611da0565b820191906000526020600020905b815481529060010190602001808311611d8357829003601f168201915b505050505081525050915050919050565b600081815261012f60205260408120546001600160a01b031680610a655760405162461bcd60e51b815260206004820152602960248201527f4552433732313a206f776e657220717565727920666f72206e6f6e657869737460448201526832b73a103a37b5b2b760b91b606482015260840161099e565b60c9546001600160a01b03163314611e535760405162461bcd60e51b815260040161099e906150ac565b6000611e5d61334a565b60030180546001600160a01b0319166001600160a01b03939093169290921790915550565b60006001600160a01b038216611eed5760405162461bcd60e51b815260206004820152602a60248201527f4552433732313a2062616c616e636520717565727920666f7220746865207a65604482015269726f206164647265737360b01b606482015260840161099e565b506001600160a01b03166000908152610130602052604090205490565b60c9546001600160a01b03163314611f345760405162461bcd60e51b815260040161099e906150ac565b611f3e6000613dff565b565b600080611f4b61334a565b5463ffffffff1692915050565b600080611f6361334a565b600201546001600160a01b031692915050565b60c9546001600160a01b03163314611fa05760405162461bcd60e51b815260040161099e906150ac565b6000611faa61334a565b60020180546001600160a01b0319166001600160a01b03939093169290921790915550565b6000611fd961334a565b60c9549091506001600160a01b0316331480612001575060038101546001600160a01b031633145b61204d5760405162461bcd60e51b815260206004820152601d60248201527f43616c6c6572206d757374206265206f776e6572206f722061646d696e000000604482015260640161099e565b611116613e51565b606061012e8054610a7b906150e1565b611af5338383613ea9565b600054610100900460ff1680612089575060005460ff16155b6120a55760405162461bcd60e51b815260040161099e90615948565b600054610100900460ff161580156120c7576000805461ffff19166101011790555b6120cf613f78565b612126604051806040016040528060128152602001712737bab7399021b634b2b73a102a37b5b2b760711b8152506040518060400160405280600b81526020016a1393d55394d0d31251539560aa1b815250613fed565b600061213061334a565b805464ffffffffff4216600160801b0274ffffffffff000000000000000000000000ffffffff19909116176001178155905061216b8a613dff565b888160030160006101000a8154816001600160a01b0302191690836001600160a01b03160217905550878160020160006101000a8154816001600160a01b0302191690836001600160a01b03160217905550868160000160086101000a81548163ffffffff021916908363ffffffff160217905550858160000160046101000a81548163ffffffff021916908363ffffffff1602179055508481600001600c6101000a81548163ffffffff021916908363ffffffff160217905550838160010160008201518160000160006101000a81548163ffffffff021916908363ffffffff16021790555060208201518160000160046101000a81548160ff021916908360ff16021790555060408201518160000160056101000a81548161ffff021916908361ffff16021790555060608201518160000160076101000a81548161ffff021916908361ffff16021790555060808201518160000160096101000a81548161ffff021916908361ffff16021790555060a082015181600001600b6101000a81548161ffff021916908361ffff16021790555060c082015181600001600d6101000a81548160ff021916908360ff160217905550905050828160050160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555050801561235f576000805461ff00191690555b505050505050505050565b60c9546001600160a01b031633146123945760405162461bcd60e51b815260040161099e906150ac565b600061239e61334a565b63ffffffff8416600081815260048301602052604090819020805486151560ff1990911617905551919250907f0f437477476c892b5eab47c4de7c7b038039c74ddde189b97d3315378149d7cb906123fb90851515815260200190565b60405180910390a2505050565b60008061241361334a565b63ffffffff8416600090815260048201602052604090208054919250906115dd906001600160601b03600160681b82048116916101009004166153f5565b61245b3383613475565b6124775760405162461bcd60e51b815260040161099e9061543c565b610dce84848484614074565b600061248d61334a565b90503361249f63ffffffff8816611db1565b6001600160a01b0316146124f55760405162461bcd60e51b815260206004820152601b60248201527f4e6f756e73436c69656e74546f6b656e3a206e6f74206f776e65720000000000604482015260640161099e565b63ffffffff8616600090815260048201602052604090206001810161251b8688836157d0565b506002810161252b8486836157d0565b508663ffffffff167f0bee293e8de088ced65538b9072d95ce36471240b1de1e8193ab5e93912945838787878760405161256894939291906158b8565b60405180910390a250505050505050565b6060600061258561334a565b600581015463ffffffff8516600090815260048084016020526040918290209151635fa2601560e01b81529394506001600160a01b0390921692635fa26015926125d3928892909101615a13565b600060405180830381865afa1580156125f0573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526126189190810190615a92565b9392505050565b60975460ff16156126425760405162461bcd60e51b815260040161099e906153cb565b60005a9050600061265161334a565b905061265b614750565b6001612665611f40565b61266f91906158f2565b63ffffffff90811682528254600160401b90041660e08201526040805163368d719960e21b815290516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169163da35c6649160048083019260209291908290030181865afa1580156126ed573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127119190615aff565b8663ffffffff16111561275b5760405162461bcd60e51b8152602060048201526012602482015271189859081b185cdd141c9bdc1bdcd85b125960721b604482015260640161099e565b8060e0015163ffffffff168663ffffffff1610156127b05760405162461bcd60e51b8152602060048201526012602482015271189859081b185cdd141c9bdc1bdcd85b125960721b604482015260640161099e565b6127ec8585808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152506140a792505050565b6128385760405162461bcd60e51b815260206004820152601760248201527f6d75737420626520736f72746564202620756e69717565000000000000000000604482015260640161099e565b60e08101516040516337e06f7160e11b81526000916001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001691636fc0dee291612890918b908b908b90600401615b18565b600060405180830381865afa1580156128ad573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526128d5919081019061560d565b90506128e2876001615752565b835463ffffffff91909116600160401b026bffffffff0000000000000000199091161783558051819061291790600190615245565b8151811061292757612927615258565b60209081029190910101516101008301819052835460c090910151600091829161295e91600160601b900463ffffffff1690610afe565b909250905061296e816001615752565b855463ffffffff91909116600160601b0263ffffffff60601b19909116178555816129db5760405162461bcd60e51b815260206004820152601a60248201527f61756374696f6e526576656e7565206d757374206265203e2030000000000000604482015260640161099e565b6001850154612710906129fb9065010000000000900461ffff168461590f565b612a059190615926565b60a0850152600185015461271090612a2890600160381b900461ffff168461590f565b612a329190615926565b60c08501526001850154600160481b900461ffff1660005b8451811015612c26576000612a99868381518110612a6a57612a6a615258565b602002602001015160000151878481518110612a8857612a88615258565b602002602001015160200151614127565b9050804311612af95760405162461bcd60e51b815260206004820152602660248201527f616c6c2070726f706f73616c73206d75737420626520646f6e65207769746820604482015265766f74696e6760d01b606482015260840161099e565b6127108361ffff16878481518110612b1357612b13615258565b602002602001015160a00151612b29919061590f565b612b339190615926565b868381518110612b4557612b45615258565b6020026020010151604001511015612b8057858281518110612b6957612b69615258565b60200260200101612b786147ad565b905250612c1e565b866040018051612b8f9061576f565b90528551600090879084908110612ba857612ba8615258565b602002602001015160800151878481518110612bc657612bc6615258565b602002602001015160600151888581518110612be457612be4615258565b602002602001015160400151612bfa91906158df565b612c0491906158df565b90508088602001818151612c1891906158df565b90525050505b600101612a4a565b506000856040015111612c7b5760405162461bcd60e51b815260206004820152601e60248201527f6174206c65617374206f6e6520656c696769626c652070726f706f73616c0000604482015260640161099e565b6001860154604086015164010000000090910460ff161115612d135760018601548654612cbc9163ffffffff1690600160801b900464ffffffffff16615b7e565b64ffffffffff1685610100015160c0015111612d135760405162461bcd60e51b81526020600482015260166024820152751b9bdd08195b9bdd59da081d1a5b59481c185cdcd95960521b604482015260640161099e565b61010085015160c00151865464ffffffffff909116600160801b0264ffffffffff60801b19909116178655604085015160a0860151612d529190615926565b6060860152602085015160c0860151612d6b9190615926565b6080860181905260e086015160608701516040517f2ef994c844705307ed8c337d3e4d748351936a138a7ab489f2436be490d049f693612dd993928f9289929063ffffffff958616815293909416602084015260408301919091526060820152608081019190915260a00190565b60405180910390a16000612df08660000151613a63565b90506000896001600160401b03811115612e0c57612e0c614b1f565b604051908082528060200260200182016040528015612e35578160200160208202803683370190505b50905060005b86518110156130b557868181518110612e5657612e56615258565b602002602001015160000151600003156130ad576000878281518110612e7e57612e7e615258565b602002602001015160e0015190508063ffffffff16600014158015612eb35750886000015163ffffffff168163ffffffff1611155b15612eca576060890151612eca9085908390613b52565b600080898481518110612edf57612edf615258565b60200260200101516101000151905060005b8e811015612fec578f8f82818110612f0b57612f0b615258565b9050602002016020810190612f2091906149fa565b93506000828281518110612f3657612f36615258565b60200260200101516000015163ffffffff169050868281518110612f5c57612f5c615258565b602002602001015180612f6f5750600081115b878381518110612f8157612f81615258565b9115156020928302919091019091015263ffffffff851615801590612fb657508c6000015163ffffffff168563ffffffff1611155b15612fd757612fd7858e6080015183612fcf919061590f565b8a9190613b52565b612fe181856158df565b935050600101612ef1565b50898481518110612fff57612fff615258565b6020026020010151608001518a858151811061301d5761301d615258565b6020026020010151606001518b868151811061303b5761303b615258565b60200260200101516040015161305191906158df565b61305b91906158df565b82146130a95760405162461bcd60e51b815260206004820152601760248201527f6e6f7420616c6c20766f746573206163636f756e746564000000000000000000604482015260640161099e565b5050505b600101612e3b565b5060005b8151811015613130578181815181106130d4576130d4615258565b60200260200101516131285760405162461bcd60e51b815260206004820152601c60248201527f616c6c20636c69656e744964206d757374206861766520766f74657300000000604482015260640161099e565b6001016130b9565b50600061313c83613c51565b905060005b818163ffffffff16101561321d57600061315b8583613c70565b905061316a8160200151613cba565b815163ffffffff16600090815260048d016020526040902080546001906131a090849061010090046001600160601b031661541c565b92506101000a8154816001600160601b0302191690836001600160601b03160217905550806000015163ffffffff167f8a6390ffb12581558b6798514e694cb23b44ff553c82d4e69024ab1fe2230ae2826020015160405161320491815260200190565b60405180910390a25061321681615525565b9050613141565b506002890154613236906001600160a01b03168b613d26565b50505050505050505050505050565b60008061325061334a565b54600160801b900464ffffffffff1692915050565b6001600160a01b0391821660009081526101326020908152604080832093909416825291909152205460ff1690565b60c9546001600160a01b031633146132be5760405162461bcd60e51b815260040161099e906150ac565b6001600160a01b0381166133235760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b606482015260840161099e565b61111681613dff565b60008061333761334a565b600301546001600160a01b031692915050565b7f9a06af3161ac5b0c3de4e6c981ab9d9f60b530386f5eaae00d541393fbecd70090565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b179052610a1490849061413d565b6000805b8251811015613400578281815181106133df576133df615258565b602002602001015160200151826133f691906158df565b91506001016133c4565b50919050565b60008181526101316020526040902080546001600160a01b0319166001600160a01b038416908117909155819061343c82611db1565b6001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45050565b600081815261012f60205260408120546001600160a01b03166134ef5760405162461bcd60e51b815260206004820152602c60248201527f4552433732313a206f70657261746f7220717565727920666f72206e6f6e657860448201526b34b9ba32b73a103a37b5b2b760a11b606482015260840161099e565b60006134fa83611db1565b9050806001600160a01b0316846001600160a01b031614806135355750836001600160a01b031661352a84610be2565b6001600160a01b0316145b806115dd57506115dd8185613265565b826001600160a01b031661355882611db1565b6001600160a01b0316146135c05760405162461bcd60e51b815260206004820152602960248201527f4552433732313a207472616e73666572206f6620746f6b656e2074686174206960448201526839903737ba1037bbb760b91b606482015260840161099e565b6001600160a01b0382166136225760405162461bcd60e51b8152602060048201526024808201527f4552433732313a207472616e7366657220746f20746865207a65726f206164646044820152637265737360e01b606482015260840161099e565b61362d600082613406565b6001600160a01b038316600090815261013060205260408120805460019290613657908490615245565b90915550506001600160a01b0382166000908152610130602052604081208054600192906136869084906158df565b9091555050600081815261012f602052604080822080546001600160a01b0319166001600160a01b0386811691821790925591518493918716917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4505050565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc546001600160a01b031690565b60c9546001600160a01b031633146111165760405162461bcd60e51b815260040161099e906150ac565b600061374a6136e8565b90506137558461420f565b6000835111806137625750815b156137735761377184846142b4565b505b7f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143805460ff1661388457805460ff191660011781556040516001600160a01b03831660248201526137f290869060440160408051601f198184030181529190526020810180516001600160e01b0316631b2ce7f360e11b1790526142b4565b50805460ff191681556138036136e8565b6001600160a01b0316826001600160a01b03161461387b5760405162461bcd60e51b815260206004820152602f60248201527f45524331393637557067726164653a207570677261646520627265616b73206660448201526e75727468657220757067726164657360881b606482015260840161099e565b6138848561439f565b5050505050565b60975460ff166138d45760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b604482015260640161099e565b6097805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b6001600160a01b0382166139745760405162461bcd60e51b815260206004820181905260248201527f4552433732313a206d696e7420746f20746865207a65726f2061646472657373604482015260640161099e565b600081815261012f60205260409020546001600160a01b0316156139da5760405162461bcd60e51b815260206004820152601c60248201527f4552433732313a20746f6b656e20616c7265616479206d696e74656400000000604482015260640161099e565b6001600160a01b038216600090815261013060205260408120805460019290613a049084906158df565b9091555050600081815261012f602052604080822080546001600160a01b0319166001600160a01b03861690811790915590518392907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a45050565b60408051606080820183528082526020820152600091810191909152613a8a826001615752565b63ffffffff166001600160401b03811115613aa757613aa7614b1f565b604051908082528060200260200182016040528015613ad0578160200160208202803683370190505b508152613ade826002615752565b63ffffffff166001600160401b03811115613afb57613afb614b1f565b604051908082528060200260200182016040528015613b4057816020015b6040805180820190915260008082526020820152815260200190600190039081613b195790505b50602082015260016040820152919050565b600083600001518363ffffffff1681518110613b7057613b70615258565b602002602001015190508063ffffffff16600003613c135760408401805190613b9882615525565b63ffffffff1663ffffffff1681525090508084600001518463ffffffff1681518110613bc657613bc6615258565b602002602001019063ffffffff16908163ffffffff16815250508284602001518263ffffffff1681518110613bfd57613bfd615258565b602090810291909101015163ffffffff90911690525b8184602001518263ffffffff1681518110613c3057613c30615258565b6020026020010151602001818151613c4891906158df565b90525050505050565b600060018260400151613c6491906158f2565b63ffffffff1692915050565b60408051808201909152600080825260208201526020830151613c94836001615752565b63ffffffff1681518110613caa57613caa615258565b6020026020010151905092915050565b60006001600160601b03821115613d225760405162461bcd60e51b815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203960448201526536206269747360d01b606482015260840161099e565b5090565b6040516370a0823160e01b81523060048201526000906001600160a01b038416906370a0823190602401602060405180830381865afa158015613d6d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613d919190615aff565b905080600003613da057505050565b6000613db148642e90edd0006143df565b90506000613dc53a637735940084016143df565b90506000618ca05a86030190506000613de0828402866143df565b9050613df66001600160a01b038816328361336e565b50505050505050565b60c980546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b60975460ff1615613e745760405162461bcd60e51b815260040161099e906153cb565b6097805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586139013390565b816001600160a01b0316836001600160a01b031603613f0a5760405162461bcd60e51b815260206004820152601960248201527f4552433732313a20617070726f766520746f2063616c6c657200000000000000604482015260640161099e565b6001600160a01b0383811660008181526101326020908152604080832094871680845294825291829020805460ff191686151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a3505050565b600054610100900460ff1680613f91575060005460ff16155b613fad5760405162461bcd60e51b815260040161099e90615948565b600054610100900460ff16158015613fcf576000805461ffff19166101011790555b6097805460ff191690558015611116576000805461ff001916905550565b600054610100900460ff1680614006575060005460ff16155b6140225760405162461bcd60e51b815260040161099e90615948565b600054610100900460ff16158015614044576000805461ffff19166101011790555b61404c6143ee565b6140546143ee565b61405e8383614459565b8015610a14576000805461ff0019169055505050565b61407f848484613545565b61408b848484846144e2565b610dce5760405162461bcd60e51b815260040161099e90615b9c565b8051600090818381836140bc576140bc615258565b602002602001015190506000600190505b8281101561411c5760008582815181106140e9576140e9615258565b602002602001015190508263ffffffff168163ffffffff16116141125750600095945050505050565b91506001016140cd565b506001949350505050565b60008183116141365781612618565b5090919050565b6000614192826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166145e09092919063ffffffff16565b805190915015610a1457808060200190518101906141b09190615bee565b610a145760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b606482015260840161099e565b803b6142735760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b606482015260840161099e565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80546001600160a01b0319166001600160a01b0392909216919091179055565b6060823b6143135760405162461bcd60e51b815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f6044820152651b9d1c9858dd60d21b606482015260840161099e565b600080846001600160a01b03168460405161432e9190615c0b565b600060405180830381855af49150503d8060008114614369576040519150601f19603f3d011682016040523d82523d6000602084013e61436e565b606091505b50915091506143968282604051806060016040528060278152602001615d41602791396145ef565b95945050505050565b6143a88161420f565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b60008183106141365781612618565b600054610100900460ff1680614407575060005460ff16155b6144235760405162461bcd60e51b815260040161099e90615948565b600054610100900460ff16158015614445576000805461ffff19166101011790555b8015611116576000805461ff001916905550565b600054610100900460ff1680614472575060005460ff16155b61448e5760405162461bcd60e51b815260040161099e90615948565b600054610100900460ff161580156144b0576000805461ffff19166101011790555b61012d6144bd8482615c27565b5061012e6144cb8382615c27565b508015610a14576000805461ff0019169055505050565b60006001600160a01b0384163b156145d857604051630a85bd0160e11b81526001600160a01b0385169063150b7a0290614526903390899088908890600401615ce6565b6020604051808303816000875af1925050508015614561575060408051601f3d908101601f1916820190925261455e91810190615d23565b60015b6145be573d80801561458f576040519150601f19603f3d011682016040523d82523d6000602084013e614594565b606091505b5080516000036145b65760405162461bcd60e51b815260040161099e90615b9c565b805181602001fd5b6001600160e01b031916630a85bd0160e11b1490506115dd565b5060016115dd565b60606115dd8484600085614628565b606083156145fe575081612618565b82511561460e5782518084602001fd5b8160405162461bcd60e51b815260040161099e9190614905565b6060824710156146895760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b606482015260840161099e565b843b6146d75760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161099e565b600080866001600160a01b031685876040516146f39190615c0b565b60006040518083038185875af1925050503d8060008114614730576040519150601f19603f3d011682016040523d82523d6000602084013e614735565b606091505b50915091506147458282866145ef565b979650505050505050565b604051806101200160405280600063ffffffff168152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600063ffffffff1681526020016147a86147ad565b905290565b60405180610120016040528060008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600063ffffffff168152602001606081525090565b6001600160a01b038116811461111657600080fd5b803561481f816147ff565b919050565b60006020828403121561483657600080fd5b8135612618816147ff565b60008060006060848603121561485657600080fd5b8335614861816147ff565b92506020840135614871816147ff565b929592945050506040919091013590565b6001600160e01b03198116811461111657600080fd5b6000602082840312156148aa57600080fd5b813561261881614882565b60005b838110156148d05781810151838201526020016148b8565b50506000910152565b600081518084526148f18160208601602086016148b5565b601f01601f19169290920160200192915050565b60208152600061261860208301846148d9565b6000806040838503121561492b57600080fd5b50508035926020909101359150565b60006020828403121561494c57600080fd5b5035919050565b6000806040838503121561496657600080fd5b8235614971816147ff565b946020939093013593505050565b600060e0828403121561340057600080fd5b63ffffffff8116811461111657600080fd5b6000806000606084860312156149b857600080fd5b83356149c381614991565b925060208401356149d3816147ff565b915060408401356001600160601b03811681146149ef57600080fd5b809150509250925092565b600060208284031215614a0c57600080fd5b813561261881614991565b60008151808452602080850194506020840160005b83811015614a4e57815163ffffffff1687529582019590820190600101614a2c565b509495945050505050565b6020815260006126186020830184614a17565b60008083601f840112614a7e57600080fd5b5081356001600160401b03811115614a9557600080fd5b602083019150836020828501011115614aad57600080fd5b9250929050565b60008060008060408587031215614aca57600080fd5b84356001600160401b0380821115614ae157600080fd5b614aed88838901614a6c565b90965094506020870135915080821115614b0657600080fd5b50614b1387828801614a6c565b95989497509550505050565b634e487b7160e01b600052604160045260246000fd5b60405160e081016001600160401b0381118282101715614b5757614b57614b1f565b60405290565b60405160a081016001600160401b0381118282101715614b5757614b57614b1f565b604080519081016001600160401b0381118282101715614b5757614b57614b1f565b60405161012081016001600160401b0381118282101715614b5757614b57614b1f565b604051601f8201601f191681016001600160401b0381118282101715614bec57614bec614b1f565b604052919050565b60006001600160401b03821115614c0d57614c0d614b1f565b50601f01601f191660200190565b600082601f830112614c2c57600080fd5b8135614c3f614c3a82614bf4565b614bc4565b818152846020838601011115614c5457600080fd5b816020850160208301376000918101602001919091529392505050565b60008060408385031215614c8457600080fd5b8235614c8f816147ff565b915060208301356001600160401b03811115614caa57600080fd5b614cb685828601614c1b565b9150509250929050565b60208152815115156020820152600060208301516001600160601b038082166040850152806040860151166060850152505066ffffffffffffff6060840151166080830152608083015160c060a0840152614d1e60e08401826148d9565b905060a0840151601f198483030160c085015261439682826148d9565b801515811461111657600080fd5b60008060408385031215614d5c57600080fd5b8235614d67816147ff565b91506020830135614d7781614d3b565b809150509250929050565b60ff8116811461111657600080fd5b803561481f81614d82565b61ffff8116811461111657600080fd5b803561481f81614d9c565b600080600080600080600080888a036101c0811215614dd557600080fd5b8935614de0816147ff565b985060208a0135614df0816147ff565b975060408a0135614e00816147ff565b965060608a0135614e1081614991565b955060808a0135614e2081614991565b945060a08a0135614e3081614991565b935060e060bf1982011215614e4457600080fd5b50614e4d614b35565b60c08a0135614e5b81614991565b815260e08a0135614e6b81614d82565b60208201526101008a0135614e7f81614d9c565b60408201526101208a0135614e9381614d9c565b6060820152614ea56101408b01614dac565b6080820152614eb76101608b01614dac565b60a0820152614ec96101808b01614d91565b60c08201529150614edd6101a08a01614814565b90509295985092959890939650565b60008060408385031215614eff57600080fd5b8235614d6781614991565b60008060008060808587031215614f2057600080fd5b8435614f2b816147ff565b93506020850135614f3b816147ff565b92506040850135915060608501356001600160401b03811115614f5d57600080fd5b614f6987828801614c1b565b91505092959194509250565b600080600080600060608688031215614f8d57600080fd5b8535614f9881614991565b945060208601356001600160401b0380821115614fb457600080fd5b614fc089838a01614a6c565b90965094506040880135915080821115614fd957600080fd5b50614fe688828901614a6c565b969995985093965092949392505050565b60008060006040848603121561500c57600080fd5b833561501781614991565b925060208401356001600160401b038082111561503357600080fd5b818601915086601f83011261504757600080fd5b81358181111561505657600080fd5b8760208260051b850101111561506b57600080fd5b6020830194508093505050509250925092565b6000806040838503121561509157600080fd5b823561509c816147ff565b91506020830135614d77816147ff565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b600181811c908216806150f557607f821691505b60208210810361340057634e487b7160e01b600052602260045260246000fd5b60006001600160401b0382111561512e5761512e614b1f565b5060051b60200190565b805161481f81614991565b6000602080838503121561515657600080fd5b82516001600160401b0381111561516c57600080fd5b8301601f8101851361517d57600080fd5b805161518b614c3a82615115565b81815260a091820283018401918482019190888411156151aa57600080fd5b938501935b838510156152235780858a0312156151c75760008081fd5b6151cf614b5d565b85516151da81614991565b815285870151878201526040808701516151f3816147ff565b908201526060868101519082015260808087015161521081614991565b90820152835293840193918501916151af565b50979650505050505050565b634e487b7160e01b600052601160045260246000fd5b81810381811115610a6557610a6561522f565b634e487b7160e01b600052603260045260246000fd5b60008135610a6581614d82565b60008135610a6581614d9c565b813561529381614991565b63ffffffff8116905081548163ffffffff19821617835560208401356152b881614d82565b64ff000000008160201b169050808364ffffffffff1984161717845560408501356152e281614d9c565b66ffff00000000008160281b168466ffffffffffffff198516178317178555505050506153386153146060840161527b565b825468ffff00000000000000191660389190911b68ffff0000000000000016178255565b61536f6153476080840161527b565b82546affff000000000000000000191660489190911b6affff00000000000000000016178255565b61539e61537e60a0840161527b565b82805461ffff60581b191660589290921b61ffff60581b16919091179055565b611af56153ad60c0840161526e565b82805460ff60681b191660689290921b60ff60681b16919091179055565b60208082526010908201526f14185d5cd8589b194e881c185d5cd95960821b604082015260600190565b6001600160601b038281168282160390808211156154155761541561522f565b5092915050565b6001600160601b038181168382160190808211156154155761541561522f565b60208082526031908201527f4552433732313a207472616e736665722063616c6c6572206973206e6f74206f6040820152701ddb995c881b9bdc88185c1c1c9bdd9959607a1b606082015260800190565b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b19195b1959d85d1958d85b1b60a21b606082015260800190565b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b6163746976652070726f787960a01b606082015260800190565b600063ffffffff80831681810361553e5761553e61522f565b6001019392505050565b600063ffffffff8086168352808516602084015250606060408301526143966060830184614a17565b600082601f83011261558257600080fd5b81516020615592614c3a83615115565b82815260069290921b840181019181810190868411156155b157600080fd5b8286015b8481101561560257604081890312156155ce5760008081fd5b6155d6614b7f565b81516155e181614991565b8152818501516155f081614991565b818601528352918301916040016155b5565b509695505050505050565b6000602080838503121561562057600080fd5b82516001600160401b038082111561563757600080fd5b818501915085601f83011261564b57600080fd5b8151615659614c3a82615115565b81815260059190911b8301840190848101908883111561567857600080fd5b8585015b83811015615745578051858111156156945760008081fd5b8601610120818c03601f19018113156156ad5760008081fd5b6156b5614ba1565b8983015181526040808401518b830152606080850151828401526080915081850151818401525060a0808501518284015260c0915081850151818401525060e08085015182840152610100915061570d828601615138565b908301529183015191888311156157245760008081fd5b6157328e8c85870101615571565b908201528552505091860191860161567c565b5098975050505050505050565b63ffffffff8181168382160190808211156154155761541561522f565b6000600182016157815761578161522f565b5060010190565b601f821115610a14576000816000526020600020601f850160051c810160208610156157b15750805b601f850160051c820191505b81811015610fdb578281556001016157bd565b6001600160401b038311156157e7576157e7614b1f565b6157fb836157f583546150e1565b83615788565b6000601f84116001811461582f57600085156158175750838201355b600019600387901b1c1916600186901b178355613884565b600083815260209020601f19861690835b828110156158605786850135825560209485019460019092019101615840565b508682101561587d5760001960f88860031b161c19848701351681555b505060018560011b0183555050505050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b6040815260006158cc60408301868861588f565b828103602084015261474581858761588f565b80820180821115610a6557610a6561522f565b63ffffffff8281168282160390808211156154155761541561522f565b8082028115828204841417610a6557610a6561522f565b60008261594357634e487b7160e01b600052601260045260246000fd5b500490565b6020808252602e908201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160408201526d191e481a5b9a5d1a585b1a5e995960921b606082015260800190565b600081546159a3816150e1565b8085526020600183811680156159c057600181146159da57615a08565b60ff1985168884015283151560051b880183019550615a08565b866000528260002060005b85811015615a005781548a82018601529083019084016159e5565b890184019650505b505050505092915050565b828152604060208201526000825460ff8116151560408401526001600160601b03808260081c166060850152615a5960808501828460681c166001600160601b03169052565b5060c81c60a083015260c080830152615a79610100830160018501615996565b828103603f190160e08401526143968160028601615996565b600060208284031215615aa457600080fd5b81516001600160401b03811115615aba57600080fd5b8201601f81018413615acb57600080fd5b8051615ad9614c3a82614bf4565b818152856020838501011115615aee57600080fd5b6143968260208301602086016148b5565b600060208284031215615b1157600080fd5b5051919050565b60006060820163ffffffff808816845260208188166020860152606060408601528286845260808601905087935060005b87811015615b70578435615b5c81614991565b841682529382019390820190600101615b49565b509998505050505050505050565b64ffffffffff8181168382160190808211156154155761541561522f565b60208082526032908201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560408201527131b2b4bb32b91034b6b83632b6b2b73a32b960711b606082015260800190565b600060208284031215615c0057600080fd5b815161261881614d3b565b60008251615c1d8184602087016148b5565b9190910192915050565b81516001600160401b03811115615c4057615c40614b1f565b615c5481615c4e84546150e1565b84615788565b602080601f831160018114615c895760008415615c715750858301515b600019600386901b1c1916600185901b178555610fdb565b600085815260208120601f198616915b82811015615cb857888601518255948401946001909101908401615c99565b5085821015615cd65787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6001600160a01b0385811682528416602082015260408101839052608060608201819052600090615d19908301846148d9565b9695505050505050565b600060208284031215615d3557600080fd5b81516126188161488256fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a26469706673582212202e6ebd6a03d34c285839a7905009454359d5b2d0729abb4952de216b97511f3164736f6c63430008170033000000000000000000000000defbf39d0e251fc058ff44b96d40cf3347596eb9000000000000000000000000f459b7573a9c2b37ef21f2f7a1a96339e343cdd8", + "nonce": "0x136", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0xe137d6edf02ca26db8dce40dd3bb916cb94e2673d0e34e4506a0fcc8fb2d0c13", + "transactionType": "CREATE", + "contractName": "RewardsProxy", + "contractAddress": "0x0d1C1Cf2336830B14658905cFf30d249189A83BE", + "function": null, + "arguments": [ + "0x16029071Fab212E7dD59DC76f65Fac398C49Cc13", + "0xa2d8437b0000000000000000000000004de2cab22c775122ac438ed70663565b619a4cf00000000000000000000000006819e97114203100d38d3d7ec214bc3eba6d5a0b0000000000000000000000007f96daef4a54f6a52613d6272560c2bd25e913b80000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000001500000000000000000000000000000000000000000000000000000000000000150000000000000000000000000000000000000000000000000000000000000e1000000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000064000000000000000000000000000000000000000000000000000000000000003200000000000000000000000000000000000000000000000000000000000003e800000000000000000000000000000000000000000000000000000000000000960000000000000000000000000000000000000000000000000000000000000003000000000000000000000000d24ee92fbb1f75c2e90b3560cad09c11a31d39a4" + ], + "transaction": { + "type": "0x02", + "from": "0xad36c32f3c28a9214adcf50a09998de1d3b0ee06", + "gas": "0x70852", + "value": "0x0", + "data": "0x6080604052604051610556380380610556833981016040819052610022916102fc565b818161004f60017f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbd6103ca565b60008051602061050f8339815191521461006b5761006b6103eb565b61007782826000610080565b50505050610450565b610089836100ac565b6000825111806100965750805b156100a7576100a583836100ec565b505b505050565b6100b58161011a565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b6060610111838360405180606001604052806027815260200161052f602791396101b2565b90505b92915050565b803b6101835760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b60648201526084015b60405180910390fd5b60008051602061050f83398151915280546001600160a01b0319166001600160a01b0392909216919091179055565b6060833b6102115760405162461bcd60e51b815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f6044820152651b9d1c9858dd60d21b606482015260840161017a565b600080856001600160a01b03168560405161022c9190610401565b600060405180830381855af49150503d8060008114610267576040519150601f19603f3d011682016040523d82523d6000602084013e61026c565b606091505b50909250905061027d828286610289565b925050505b9392505050565b60608315610298575081610282565b8251156102a85782518084602001fd5b8160405162461bcd60e51b815260040161017a919061041d565b634e487b7160e01b600052604160045260246000fd5b60005b838110156102f35781810151838201526020016102db565b50506000910152565b6000806040838503121561030f57600080fd5b82516001600160a01b038116811461032657600080fd5b60208401519092506001600160401b038082111561034357600080fd5b818501915085601f83011261035757600080fd5b815181811115610369576103696102c2565b604051601f8201601f19908116603f01168101908382118183101715610391576103916102c2565b816040528281528860208487010111156103aa57600080fd5b6103bb8360208301602088016102d8565b80955050505050509250929050565b8181038181111561011457634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052600160045260246000fd5b600082516104138184602087016102d8565b9190910192915050565b602081526000825180602084015261043c8160408501602087016102d8565b601f01601f19169190910160400192915050565b60b18061045e6000396000f3fe608060405236601057600e6013565b005b600e5b601f601b6021565b6058565b565b600060537f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc546001600160a01b031690565b905090565b3660008037600080366000845af43d6000803e8080156076573d6000f35b3d6000fdfea2646970667358221220f940f28710c39d22f077b0b9eb5545be2c119e3af925b0e2bf403b603e71c92964736f6c63430008170033360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c656400000000000000000000000016029071fab212e7dd59dc76f65fac398c49cc13000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000001c4a2d8437b0000000000000000000000004de2cab22c775122ac438ed70663565b619a4cf00000000000000000000000006819e97114203100d38d3d7ec214bc3eba6d5a0b0000000000000000000000007f96daef4a54f6a52613d6272560c2bd25e913b80000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000001500000000000000000000000000000000000000000000000000000000000000150000000000000000000000000000000000000000000000000000000000000e1000000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000064000000000000000000000000000000000000000000000000000000000000003200000000000000000000000000000000000000000000000000000000000003e800000000000000000000000000000000000000000000000000000000000000960000000000000000000000000000000000000000000000000000000000000003000000000000000000000000d24ee92fbb1f75c2e90b3560cad09c11a31d39a400000000000000000000000000000000000000000000000000000000", + "nonce": "0x137", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + } + ], + "receipts": [ + { + "transactionHash": "0x5b7d177cab55f11783b5bb8b8147c40a241ec93da31e46bc3ec4db3604154ab8", + "transactionIndex": "0x33", + "blockHash": "0x64b3ce3f14811fc9217c75612c4125d07ea14460c9fb48c5d9f25ca5c4fe11c8", + "blockNumber": "0x50de6f", + "from": "0xaD36c32F3c28A9214ADCf50A09998de1d3b0EE06", + "to": null, + "cumulativeGasUsed": "0x4bf666", + "gasUsed": "0x14a966", + "contractAddress": "0xD24ee92FBb1F75c2e90B3560CAd09C11A31d39A4", + "logs": [], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "type": "0x2", + "effectiveGasPrice": "0x1383becb4" + }, + { + "transactionHash": "0xbc12392548073ee814ef23662978de7fdc3df93d190a33f96acee824e202c917", + "transactionIndex": "0x34", + "blockHash": "0x64b3ce3f14811fc9217c75612c4125d07ea14460c9fb48c5d9f25ca5c4fe11c8", + "blockNumber": "0x50de6f", + "from": "0xaD36c32F3c28A9214ADCf50A09998de1d3b0EE06", + "to": null, + "cumulativeGasUsed": "0x9c25a2", + "gasUsed": "0x502f3c", + "contractAddress": "0x16029071Fab212E7dD59DC76f65Fac398C49Cc13", + "logs": [], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "type": "0x2", + "effectiveGasPrice": "0x1383becb4" + }, + { + "transactionHash": "0xe137d6edf02ca26db8dce40dd3bb916cb94e2673d0e34e4506a0fcc8fb2d0c13", + "transactionIndex": "0x35", + "blockHash": "0x64b3ce3f14811fc9217c75612c4125d07ea14460c9fb48c5d9f25ca5c4fe11c8", + "blockNumber": "0x50de6f", + "from": "0xaD36c32F3c28A9214ADCf50A09998de1d3b0EE06", + "to": null, + "cumulativeGasUsed": "0xa18ef9", + "gasUsed": "0x56957", + "contractAddress": "0x0d1C1Cf2336830B14658905cFf30d249189A83BE", + "logs": [ + { + "address": "0x0d1C1Cf2336830B14658905cFf30d249189A83BE", + "topics": [ + "0xbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b", + "0x00000000000000000000000016029071fab212e7dd59dc76f65fac398c49cc13" + ], + "data": "0x", + "blockHash": "0x64b3ce3f14811fc9217c75612c4125d07ea14460c9fb48c5d9f25ca5c4fe11c8", + "blockNumber": "0x50de6f", + "transactionHash": "0xe137d6edf02ca26db8dce40dd3bb916cb94e2673d0e34e4506a0fcc8fb2d0c13", + "transactionIndex": "0x35", + "logIndex": "0x3d", + "removed": false + }, + { + "address": "0x0d1C1Cf2336830B14658905cFf30d249189A83BE", + "topics": [ + "0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000004de2cab22c775122ac438ed70663565b619a4cf0" + ], + "data": "0x", + "blockHash": "0x64b3ce3f14811fc9217c75612c4125d07ea14460c9fb48c5d9f25ca5c4fe11c8", + "blockNumber": "0x50de6f", + "transactionHash": "0xe137d6edf02ca26db8dce40dd3bb916cb94e2673d0e34e4506a0fcc8fb2d0c13", + "transactionIndex": "0x35", + "logIndex": "0x3e", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000000000400000000000000000800000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000040000010002000001000000000000000000000000000000000000020000000000000000000800000000000000000000000000000000400000000002000000000000400000000000000000000000000000000000000000000000000000000000000000000000000020000000008020000002000000000000000020000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000", + "type": "0x2", + "effectiveGasPrice": "0x1383becb4" + } + ], + "libraries": [], + "pending": [], + "returns": { + "rewards": { + "internal_type": "contract Rewards", + "value": "0x0d1C1Cf2336830B14658905cFf30d249189A83BE" + } + }, + "timestamp": 1708076130, + "chain": 11155111, + "multi": false, + "commit": "270cf0f6" +} \ No newline at end of file diff --git a/packages/nouns-contracts/contracts/NounsAuctionHousePreV2Migration.sol b/packages/nouns-contracts/contracts/NounsAuctionHousePreV2Migration.sol new file mode 100644 index 0000000000..4a1468394d --- /dev/null +++ b/packages/nouns-contracts/contracts/NounsAuctionHousePreV2Migration.sol @@ -0,0 +1,95 @@ +// SPDX-License-Identifier: GPL-3.0 + +/// @title An interim contract for storage migration between V1 and V2 + +/********************************* + * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ * + * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ * + * ░░░░░░█████████░░█████████░░░ * + * ░░░░░░██░░░████░░██░░░████░░░ * + * ░░██████░░░████████░░░████░░░ * + * ░░██░░██░░░████░░██░░░████░░░ * + * ░░██░░██░░░████░░██░░░████░░░ * + * ░░░░░░█████████░░█████████░░░ * + * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ * + * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ * + *********************************/ + +pragma solidity ^0.8.19; + +import { PausableUpgradeable } from '@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol'; +import { ReentrancyGuardUpgradeable } from '@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol'; +import { OwnableUpgradeable } from '@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol'; +import { INounsAuctionHouse } from './interfaces/INounsAuctionHouse.sol'; +import { INounsAuctionHouseV2 } from './interfaces/INounsAuctionHouseV2.sol'; + +contract NounsAuctionHousePreV2Migration is PausableUpgradeable, ReentrancyGuardUpgradeable, OwnableUpgradeable { + struct OldLayout { + address nouns; + address weth; + uint256 timeBuffer; + uint256 reservePrice; + uint8 minBidIncrementPercentage; + uint256 duration; + INounsAuctionHouse.Auction auction; + } + + struct NewLayout { + uint192 reservePrice; + uint56 timeBuffer; + uint8 minBidIncrementPercentage; + INounsAuctionHouseV2.AuctionV2 auction; + } + + uint256 private startSlot; + + constructor() { + /// @dev Make sure startSlot points to the correct slot + uint256 startSlotLocation; + assembly { + startSlotLocation := startSlot.slot + } + require(startSlotLocation == 0xc9); + } + + function migrate() public onlyOwner { + OldLayout storage oldLayout = _oldLayout(); + NewLayout storage newLayout = _newLayout(); + OldLayout memory oldLayoutCache = oldLayout; + + // Clear the old storage layout + oldLayout.nouns = address(0); + oldLayout.weth = address(0); + oldLayout.timeBuffer = 0; + oldLayout.reservePrice = 0; + oldLayout.minBidIncrementPercentage = 0; + oldLayout.duration = 0; + oldLayout.auction = INounsAuctionHouse.Auction(0, 0, 0, 0, payable(0), false); + + // Populate the new layout from the cache + newLayout.reservePrice = uint192(oldLayoutCache.reservePrice); + newLayout.timeBuffer = uint56(oldLayoutCache.timeBuffer); + newLayout.minBidIncrementPercentage = oldLayoutCache.minBidIncrementPercentage; + newLayout.auction = INounsAuctionHouseV2.AuctionV2({ + nounId: uint96(oldLayoutCache.auction.nounId), + clientId: 0, + amount: uint128(oldLayoutCache.auction.amount), + startTime: uint40(oldLayoutCache.auction.startTime), + endTime: uint40(oldLayoutCache.auction.endTime), + bidder: oldLayoutCache.auction.bidder, + settled: oldLayoutCache.auction.settled + }); + } + + function _oldLayout() internal pure returns (OldLayout storage layout) { + assembly { + layout.slot := startSlot.slot + } + } + + function _newLayout() internal pure returns (NewLayout storage layout) { + assembly { + layout.slot := startSlot.slot + } + } +} diff --git a/packages/nouns-contracts/contracts/NounsAuctionHouseV2.sol b/packages/nouns-contracts/contracts/NounsAuctionHouseV2.sol new file mode 100644 index 0000000000..1ceacec99b --- /dev/null +++ b/packages/nouns-contracts/contracts/NounsAuctionHouseV2.sol @@ -0,0 +1,555 @@ +// SPDX-License-Identifier: GPL-3.0 + +/// @title The Nouns DAO auction house + +/********************************* + * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ * + * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ * + * ░░░░░░█████████░░█████████░░░ * + * ░░░░░░██░░░████░░██░░░████░░░ * + * ░░██████░░░████████░░░████░░░ * + * ░░██░░██░░░████░░██░░░████░░░ * + * ░░██░░██░░░████░░██░░░████░░░ * + * ░░░░░░█████████░░█████████░░░ * + * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ * + * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ * + *********************************/ + +// LICENSE +// NounsAuctionHouse.sol is a modified version of Zora's AuctionHouse.sol: +// https://github.com/ourzora/auction-house/blob/54a12ec1a6cf562e49f0a4917990474b11350a2d/contracts/AuctionHouse.sol +// +// AuctionHouse.sol source code Copyright Zora licensed under the GPL-3.0 license. +// With modifications by Nounders DAO. + +pragma solidity ^0.8.19; + +import { PausableUpgradeable } from '@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol'; +import { ReentrancyGuardUpgradeable } from '@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol'; +import { OwnableUpgradeable } from '@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol'; +import { IERC20 } from '@openzeppelin/contracts/token/ERC20/IERC20.sol'; +import { INounsAuctionHouseV2 } from './interfaces/INounsAuctionHouseV2.sol'; +import { INounsToken } from './interfaces/INounsToken.sol'; +import { IWETH } from './interfaces/IWETH.sol'; + +/** + * @dev The contract inherits from PausableUpgradeable & ReentrancyGuardUpgradeable most of all the keep the same + * storage layout as the NounsAuctionHouse contract + */ +contract NounsAuctionHouseV2 is + INounsAuctionHouseV2, + PausableUpgradeable, + ReentrancyGuardUpgradeable, + OwnableUpgradeable +{ + /// @notice A hard-coded cap on time buffer to prevent accidental auction disabling if set with a very high value. + uint56 public constant MAX_TIME_BUFFER = 1 days; + + /// @notice The Nouns ERC721 token contract + INounsToken public immutable nouns; + + /// @notice The address of the WETH contract + address public immutable weth; + + /// @notice The duration of a single auction + uint256 public immutable duration; + + /// @notice The minimum price accepted in an auction + uint192 public reservePrice; + + /// @notice The minimum amount of time left in an auction after a new bid is created + uint56 public timeBuffer; + + /// @notice The minimum percentage difference between the last bid amount and the current bid + uint8 public minBidIncrementPercentage; + + /// @notice The active auction + INounsAuctionHouseV2.AuctionV2 public auctionStorage; + + /// @notice The Nouns price feed state + mapping(uint256 => SettlementState) settlementHistory; + + constructor(INounsToken _nouns, address _weth, uint256 _duration) initializer { + nouns = _nouns; + weth = _weth; + duration = _duration; + } + + /** + * @notice Initialize the auction house and base contracts, + * populate configuration values, and pause the contract. + * @dev This function can only be called once. + */ + function initialize( + uint192 _reservePrice, + uint56 _timeBuffer, + uint8 _minBidIncrementPercentage + ) external initializer { + __Pausable_init(); + __ReentrancyGuard_init(); + __Ownable_init(); + + _pause(); + + reservePrice = _reservePrice; + timeBuffer = _timeBuffer; + minBidIncrementPercentage = _minBidIncrementPercentage; + } + + /** + * @notice Settle the current auction, mint a new Noun, and put it up for auction. + */ + function settleCurrentAndCreateNewAuction() external override whenNotPaused { + _settleAuction(); + _createAuction(); + } + + /** + * @notice Settle the current auction. + * @dev This function can only be called when the contract is paused. + */ + function settleAuction() external override whenPaused { + _settleAuction(); + } + + /** + * @notice Create a bid for a Noun, with a given amount. + * @dev This contract only accepts payment in ETH. + */ + function createBid(uint256 nounId) external payable override { + createBid(nounId, 0); + } + + /** + * @notice Create a bid for a Noun, with a given amount. + * @param nounId id of the Noun to bid on + * @param clientId the client which facilitate this action + * @dev This contract only accepts payment in ETH. + */ + function createBid(uint256 nounId, uint32 clientId) public payable override { + INounsAuctionHouseV2.AuctionV2 memory _auction = auctionStorage; + + (uint192 _reservePrice, uint56 _timeBuffer, uint8 _minBidIncrementPercentage) = ( + reservePrice, + timeBuffer, + minBidIncrementPercentage + ); + + require(_auction.nounId == nounId, 'Noun not up for auction'); + require(block.timestamp < _auction.endTime, 'Auction expired'); + require(msg.value >= _reservePrice, 'Must send at least reservePrice'); + require( + msg.value >= _auction.amount + ((_auction.amount * _minBidIncrementPercentage) / 100), + 'Must send more than last bid by minBidIncrementPercentage amount' + ); + + auctionStorage.clientId = clientId; + auctionStorage.amount = uint128(msg.value); + auctionStorage.bidder = payable(msg.sender); + + // Extend the auction if the bid was received within `timeBuffer` of the auction end time + bool extended = _auction.endTime - block.timestamp < _timeBuffer; + + emit AuctionBid(_auction.nounId, msg.sender, msg.value, extended); + if (clientId > 0) emit AuctionBidWithClientId(_auction.nounId, msg.value, clientId); + + if (extended) { + auctionStorage.endTime = _auction.endTime = uint40(block.timestamp + _timeBuffer); + emit AuctionExtended(_auction.nounId, _auction.endTime); + } + + address payable lastBidder = _auction.bidder; + + // Refund the last bidder, if applicable + if (lastBidder != address(0)) { + _safeTransferETHWithFallback(lastBidder, _auction.amount); + } + } + + /** + * @notice Get the current auction. + */ + function auction() external view returns (AuctionV2View memory) { + return + AuctionV2View({ + nounId: auctionStorage.nounId, + amount: auctionStorage.amount, + startTime: auctionStorage.startTime, + endTime: auctionStorage.endTime, + bidder: auctionStorage.bidder, + settled: auctionStorage.settled + }); + } + + /** + * @notice Pause the Nouns auction house. + * @dev This function can only be called by the owner when the + * contract is unpaused. While no new auctions can be started when paused, + * anyone can settle an ongoing auction. + */ + function pause() external override onlyOwner { + _pause(); + } + + /** + * @notice Unpause the Nouns auction house. + * @dev This function can only be called by the owner when the + * contract is paused. If required, this function will start a new auction. + */ + function unpause() external override onlyOwner { + _unpause(); + + if (auctionStorage.startTime == 0 || auctionStorage.settled) { + _createAuction(); + } + } + + /** + * @notice Set the auction time buffer. + * @dev Only callable by the owner. + */ + function setTimeBuffer(uint56 _timeBuffer) external override onlyOwner { + require(_timeBuffer <= MAX_TIME_BUFFER, 'timeBuffer too large'); + + timeBuffer = _timeBuffer; + + emit AuctionTimeBufferUpdated(_timeBuffer); + } + + /** + * @notice Set the auction reserve price. + * @dev Only callable by the owner. + */ + function setReservePrice(uint192 _reservePrice) external override onlyOwner { + reservePrice = _reservePrice; + + emit AuctionReservePriceUpdated(_reservePrice); + } + + /** + * @notice Set the auction minimum bid increment percentage. + * @dev Only callable by the owner. + */ + function setMinBidIncrementPercentage(uint8 _minBidIncrementPercentage) external override onlyOwner { + require(_minBidIncrementPercentage > 0, 'must be greater than zero'); + + minBidIncrementPercentage = _minBidIncrementPercentage; + + emit AuctionMinBidIncrementPercentageUpdated(_minBidIncrementPercentage); + } + + /** + * @notice Create an auction. + * @dev Store the auction details in the `auction` state variable and emit an AuctionCreated event. + * If the mint reverts, the minter was updated without pausing this contract first. To remedy this, + * catch the revert and pause this contract. + */ + function _createAuction() internal { + try nouns.mint() returns (uint256 nounId) { + uint40 startTime = uint40(block.timestamp); + uint40 endTime = startTime + uint40(duration); + + auctionStorage = AuctionV2({ + nounId: uint96(nounId), + clientId: 0, + amount: 0, + startTime: startTime, + endTime: endTime, + bidder: payable(0), + settled: false + }); + + emit AuctionCreated(nounId, startTime, endTime); + } catch Error(string memory) { + _pause(); + } + } + + /** + * @notice Settle an auction, finalizing the bid and paying out to the owner. + * @dev If there are no bids, the Noun is burned. + */ + function _settleAuction() internal { + INounsAuctionHouseV2.AuctionV2 memory _auction = auctionStorage; + + require(_auction.startTime != 0, "Auction hasn't begun"); + require(!_auction.settled, 'Auction has already been settled'); + require(block.timestamp >= _auction.endTime, "Auction hasn't completed"); + + auctionStorage.settled = true; + + if (_auction.bidder == address(0)) { + nouns.burn(_auction.nounId); + } else { + nouns.transferFrom(address(this), _auction.bidder, _auction.nounId); + } + + if (_auction.amount > 0) { + _safeTransferETHWithFallback(owner(), _auction.amount); + } + + SettlementState storage settlementState = settlementHistory[_auction.nounId]; + settlementState.blockTimestamp = uint32(block.timestamp); + settlementState.amount = ethPriceToUint64(_auction.amount); + settlementState.winner = _auction.bidder; + if (_auction.clientId > 0) settlementState.clientId = _auction.clientId; + + emit AuctionSettled(_auction.nounId, _auction.bidder, _auction.amount); + if (_auction.clientId > 0) emit AuctionSettledWithClientId(_auction.nounId, _auction.clientId); + } + + /** + * @notice Transfer ETH. If the ETH transfer fails, wrap the ETH and try send it as WETH. + */ + function _safeTransferETHWithFallback(address to, uint256 amount) internal { + if (!_safeTransferETH(to, amount)) { + IWETH(weth).deposit{ value: amount }(); + IERC20(weth).transfer(to, amount); + } + } + + /** + * @notice Transfer ETH and return the success status. + * @dev This function only forwards 30,000 gas to the callee. + */ + function _safeTransferETH(address to, uint256 value) internal returns (bool) { + bool success; + assembly { + success := call(30000, to, value, 0, 0, 0, 0) + } + return success; + } + + /** + * @notice Set historic prices; only callable by the owner, which in Nouns is the treasury (timelock) contract. + * @dev This function lowers auction price accuracy from 18 decimals to 10 decimals, as part of the price history + * bit packing, to save gas. + * @param settlements The list of historic prices to set. + */ + function setPrices(SettlementNoClientId[] memory settlements) external onlyOwner { + for (uint256 i = 0; i < settlements.length; ++i) { + SettlementState storage settlementState = settlementHistory[settlements[i].nounId]; + settlementState.blockTimestamp = settlements[i].blockTimestamp; + settlementState.amount = ethPriceToUint64(settlements[i].amount); + settlementState.winner = settlements[i].winner; + } + } + + /** + * @notice Warm up the settlement state for a range of Noun IDs. + * @dev Helps lower the gas cost of auction settlement when storing settlement data + * thanks to the state slot being non-zero. + * @dev Only writes to slots where blockTimestamp is zero, meaning it will not overwrite existing data. + * @dev Skips Nounder reward nouns. + * @param startId the first Noun ID to warm up. + * @param endId end Noun ID (up to, but not including). + */ + function warmUpSettlementState(uint256 startId, uint256 endId) external { + for (uint256 i = startId; i < endId; ++i) { + // Skipping Nounder rewards, no need to warm up those slots since they are never used. + if (i <= 1820 && i % 10 == 0) continue; + + SettlementState storage settlementState = settlementHistory[i]; + if (settlementState.blockTimestamp == 0) { + settlementState.blockTimestamp = 1; + settlementState.slotWarmedUp = true; + } + } + } + + /** + * @notice Get past auction settlements. + * @dev Returns up to `auctionCount` settlements in reverse order, meaning settlements[0] will be the most recent auction price. + * Includes auctions with no bids (blockTimestamp will be > 1) + * @param auctionCount The number of price observations to get. + * @param skipEmptyValues if true, skips nounder reward ids and ids with missing data + * @return settlements An array of type `Settlement`, where each Settlement includes a timestamp, + * the Noun ID of that auction, the winning bid amount, and the winner's address. + */ + function getSettlements( + uint256 auctionCount, + bool skipEmptyValues + ) external view returns (Settlement[] memory settlements) { + uint256 latestNounId = auctionStorage.nounId; + if (!auctionStorage.settled && latestNounId > 0) { + latestNounId -= 1; + } + + settlements = new Settlement[](auctionCount); + uint256 actualCount = 0; + + SettlementState memory settlementState; + for (uint256 id = latestNounId; actualCount < auctionCount; --id) { + settlementState = settlementHistory[id]; + + if (skipEmptyValues && settlementState.blockTimestamp <= 1) { + if (id == 0) break; + continue; + } + + settlements[actualCount] = Settlement({ + blockTimestamp: settlementState.blockTimestamp, + amount: uint64PriceToUint256(settlementState.amount), + winner: settlementState.winner, + nounId: id, + clientId: settlementState.clientId + }); + ++actualCount; + + if (id == 0) break; + } + + if (auctionCount > actualCount) { + // this assembly trims the observations array, getting rid of unused cells + assembly { + mstore(settlements, actualCount) + } + } + } + + /** + * @notice Get past auction prices. + * @dev Returns prices in reverse order, meaning prices[0] will be the most recent auction price. + * Skips auctions where there was no winner, i.e. no bids. + * Skips nounder rewards noun ids. + * Reverts if getting a empty data for an auction that happened, e.g. historic data not filled + * Reverts if there's not enough auction data, i.e. reached noun id 0 + * @param auctionCount The number of price observations to get. + * @return prices An array of uint256 prices. + */ + function getPrices(uint256 auctionCount) external view returns (uint256[] memory prices) { + uint256 latestNounId = auctionStorage.nounId; + if (!auctionStorage.settled && latestNounId > 0) { + latestNounId -= 1; + } + + prices = new uint256[](auctionCount); + uint256 actualCount = 0; + + SettlementState memory settlementState; + for (uint256 id = latestNounId; id > 0 && actualCount < auctionCount; --id) { + if (id <= 1820 && id % 10 == 0) continue; // Skip Nounder reward nouns + + settlementState = settlementHistory[id]; + require(settlementState.blockTimestamp > 1, 'Missing data'); + if (settlementState.winner == address(0)) continue; // Skip auctions with no bids + + prices[actualCount] = uint64PriceToUint256(settlementState.amount); + ++actualCount; + } + + require(auctionCount == actualCount, 'Not enough history'); + } + + /** + * @notice Get all past auction settlements starting at `startId` and settled before or at `endTimestamp`. + * @param startId the first Noun ID to get prices for. + * @param endTimestamp the latest timestamp for auctions + * @param skipEmptyValues if true, skips nounder reward ids and ids with missing data + * @return settlements An array of type `Settlement`, where each Settlement includes a timestamp, + * the Noun ID of that auction, the winning bid amount, and the winner's address. + */ + function getSettlementsFromIdtoTimestamp( + uint256 startId, + uint256 endTimestamp, + bool skipEmptyValues + ) public view returns (Settlement[] memory settlements) { + uint256 maxId = auctionStorage.nounId; + require(startId <= maxId, 'startId too large'); + settlements = new Settlement[](maxId - startId + 1); + uint256 actualCount = 0; + SettlementState memory settlementState; + for (uint256 id = startId; id <= maxId; ++id) { + settlementState = settlementHistory[id]; + + if (skipEmptyValues && settlementState.blockTimestamp <= 1) continue; + + // don't include the currently auctioned noun if it hasn't settled + if ((id == maxId) && (settlementState.blockTimestamp <= 1)) continue; + + if (settlementState.blockTimestamp > endTimestamp) break; + + settlements[actualCount] = Settlement({ + blockTimestamp: settlementState.blockTimestamp, + amount: uint64PriceToUint256(settlementState.amount), + winner: settlementState.winner, + nounId: id, + clientId: settlementState.clientId + }); + ++actualCount; + } + + if (settlements.length > actualCount) { + // this assembly trims the settlements array, getting rid of unused cells + assembly { + mstore(settlements, actualCount) + } + } + } + + /** + * @notice Get a range of past auction settlements. + * @dev Returns prices in chronological order, as opposed to `getSettlements(count)` which returns prices in reverse order. + * Includes auctions with no bids (blockTimestamp will be > 1) + * @param startId the first Noun ID to get prices for. + * @param endId end Noun ID (up to, but not including). + * @param skipEmptyValues if true, skips nounder reward ids and ids with missing data + * @return settlements An array of type `Settlement`, where each Settlement includes a timestamp, + * the Noun ID of that auction, the winning bid amount, and the winner's address. + */ + function getSettlements( + uint256 startId, + uint256 endId, + bool skipEmptyValues + ) external view returns (Settlement[] memory settlements) { + settlements = new Settlement[](endId - startId); + uint256 actualCount = 0; + + SettlementState memory settlementState; + for (uint256 id = startId; id < endId; ++id) { + settlementState = settlementHistory[id]; + + if (skipEmptyValues && settlementState.blockTimestamp <= 1) continue; + + settlements[actualCount] = Settlement({ + blockTimestamp: settlementState.blockTimestamp, + amount: uint64PriceToUint256(settlementState.amount), + winner: settlementState.winner, + nounId: id, + clientId: settlementState.clientId + }); + ++actualCount; + } + + if (settlements.length > actualCount) { + // this assembly trims the settlements array, getting rid of unused cells + assembly { + mstore(settlements, actualCount) + } + } + } + + /*** + * @notice Get the client ID that facilitated the winning bid for a Noun. Returns 0 if there is no settlement data + * for the Noun in question, or if the winning bid was not facilitated by a registered client. + */ + function biddingClient(uint256 nounId) external view returns (uint32) { + return settlementHistory[nounId].clientId; + } + + /** + * @dev Convert an ETH price of 256 bits with 18 decimals, to 64 bits with 10 decimals. + * Max supported value is 1844674407.3709551615 ETH. + * + */ + function ethPriceToUint64(uint256 ethPrice) internal pure returns (uint64) { + return uint64(ethPrice / 1e8); + } + + /** + * @dev Convert a 64 bit 10 decimal price to a 256 bit 18 decimal price. + */ + function uint64PriceToUint256(uint64 price) internal pure returns (uint256) { + return uint256(price) * 1e8; + } +} diff --git a/packages/nouns-contracts/contracts/client-incentives/INounsClientTokenDescriptor.sol b/packages/nouns-contracts/contracts/client-incentives/INounsClientTokenDescriptor.sol new file mode 100644 index 0000000000..7fb69b715d --- /dev/null +++ b/packages/nouns-contracts/contracts/client-incentives/INounsClientTokenDescriptor.sol @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: GPL-3.0 + +/********************************* + * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ * + * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ * + * ░░░░░░█████████░░█████████░░░ * + * ░░░░░░██░░░████░░██░░░████░░░ * + * ░░██████░░░████████░░░████░░░ * + * ░░██░░██░░░████░░██░░░████░░░ * + * ░░██░░██░░░████░░██░░░████░░░ * + * ░░░░░░█████████░░█████████░░░ * + * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ * + * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ * + *********************************/ + +pragma solidity ^0.8.19; + +import { INounsClientTokenTypes } from './INounsClientTokenTypes.sol'; + +interface INounsClientTokenDescriptor { + function tokenURI( + uint256 tokenId, + INounsClientTokenTypes.ClientMetadata calldata metadata + ) external view returns (string memory); +} diff --git a/packages/nouns-contracts/contracts/client-incentives/INounsClientTokenTypes.sol b/packages/nouns-contracts/contracts/client-incentives/INounsClientTokenTypes.sol new file mode 100644 index 0000000000..3973ae6041 --- /dev/null +++ b/packages/nouns-contracts/contracts/client-incentives/INounsClientTokenTypes.sol @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: GPL-3.0 + +/********************************* + * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ * + * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ * + * ░░░░░░█████████░░█████████░░░ * + * ░░░░░░██░░░████░░██░░░████░░░ * + * ░░██████░░░████████░░░████░░░ * + * ░░██░░██░░░████░░██░░░████░░░ * + * ░░██░░██░░░████░░██░░░████░░░ * + * ░░░░░░█████████░░█████████░░░ * + * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ * + * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ * + *********************************/ + +pragma solidity ^0.8.19; + +interface INounsClientTokenTypes { + struct ClientMetadata { + /// @notice Whether the DAO has approved the client to withdraw their rewards. + bool approved; + /// @notice The amount of reward tokens this client has been rewarded. + uint96 rewarded; + /// @notice The amount of tokens this client has withdrawn. + uint96 withdrawn; + /// @dev A gap for future storage needs. + uint56 __gap; + /// @notice The client's display name. + string name; + /// @notice The client's description, e.g. its URL. + string description; + } +} diff --git a/packages/nouns-contracts/contracts/client-incentives/NounsClientTokenDescriptor.sol b/packages/nouns-contracts/contracts/client-incentives/NounsClientTokenDescriptor.sol new file mode 100644 index 0000000000..a7a8949151 --- /dev/null +++ b/packages/nouns-contracts/contracts/client-incentives/NounsClientTokenDescriptor.sol @@ -0,0 +1,121 @@ +// SPDX-License-Identifier: GPL-3.0 + +/// @title The client incentives NFT descriptor + +/********************************* + * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ * + * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ * + * ░░░░░░█████████░░█████████░░░ * + * ░░░░░░██░░░████░░██░░░████░░░ * + * ░░██████░░░████████░░░████░░░ * + * ░░██░░██░░░████░░██░░░████░░░ * + * ░░██░░██░░░████░░██░░░████░░░ * + * ░░░░░░█████████░░█████████░░░ * + * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ * + * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ * + *********************************/ + +pragma solidity ^0.8.19; + +import { INounsClientTokenDescriptor } from './INounsClientTokenDescriptor.sol'; +import { INounsClientTokenTypes } from './INounsClientTokenTypes.sol'; +import { Base64 } from 'base64-sol/base64.sol'; +import { Strings } from '@openzeppelin/contracts/utils/Strings.sol'; +import { ETHString } from '../libs/ETHString.sol'; + +contract NounsClientTokenDescriptor is INounsClientTokenDescriptor { + using Strings for uint256; + using ETHString for uint96; + + string private constant _SVG_START_TAG = + ''; + string private constant _SVG_END_TAG = + ''; + string private constant TEXT_SPAN_END = ''; + string private constant ETH = ' ETH'; + string private constant CLIENT_NAME_START = + 'Client Name:'; + string private constant STATUS_START = + 'Status:'; + string private constant TOTAL_REWARDED_START = + 'Total Rewarded:'; + string private constant CLIENT_ID_START = + 'Client ID:'; + string private constant CLIENT_DESCRIPTION_START = + 'Client Description:'; + + function tokenURI( + uint256 tokenId, + INounsClientTokenTypes.ClientMetadata memory metadata + ) external pure returns (string memory) { + string memory name = string(abi.encodePacked('Nouns Client ', tokenId.toString(), ': ', metadata.name)); + string memory image = Base64.encode( + bytes(abi.encodePacked(_SVG_START_TAG, _generateSVGText(tokenId, metadata), _SVG_END_TAG)) + ); + + return + string( + abi.encodePacked( + 'data:application/json;base64,', + Base64.encode( + bytes( + abi.encodePacked( + '{"name":"', + name, + '", "description":"', + metadata.description, + '", "image": "', + 'data:image/svg+xml;base64,', + image, + '"}' + ) + ) + ) + ) + ); + } + + function _generateSVGText( + uint256 tokenId, + INounsClientTokenTypes.ClientMetadata memory metadata + ) private pure returns (string memory) { + return + string( + abi.encodePacked( + _clientNameSVG(metadata), + _clientStatusSVG(metadata), + _totalRewardedSVG(metadata), + _clientIdSVG(tokenId), + _clientDescriptionSVG(metadata) + ) + ); + } + + function _clientNameSVG( + INounsClientTokenTypes.ClientMetadata memory metadata + ) private pure returns (string memory) { + return string(abi.encodePacked(CLIENT_NAME_START, metadata.name, TEXT_SPAN_END)); + } + + function _clientStatusSVG( + INounsClientTokenTypes.ClientMetadata memory metadata + ) private pure returns (string memory) { + return string(abi.encodePacked(STATUS_START, metadata.approved ? 'Approved' : 'Not Approved', TEXT_SPAN_END)); + } + + function _totalRewardedSVG( + INounsClientTokenTypes.ClientMetadata memory metadata + ) private pure returns (string memory) { + return string(abi.encodePacked(TOTAL_REWARDED_START, metadata.rewarded.toETHString(), ETH, TEXT_SPAN_END)); + } + + function _clientIdSVG(uint256 tokenId) private pure returns (string memory) { + return string(abi.encodePacked(CLIENT_ID_START, tokenId.toString(), TEXT_SPAN_END)); + } + + function _clientDescriptionSVG( + INounsClientTokenTypes.ClientMetadata memory metadata + ) private pure returns (string memory) { + return string(abi.encodePacked(CLIENT_DESCRIPTION_START, metadata.description, TEXT_SPAN_END)); + } +} diff --git a/packages/nouns-contracts/contracts/client-incentives/Rewards.sol b/packages/nouns-contracts/contracts/client-incentives/Rewards.sol new file mode 100644 index 0000000000..b31b4afc45 --- /dev/null +++ b/packages/nouns-contracts/contracts/client-incentives/Rewards.sol @@ -0,0 +1,786 @@ +// SPDX-License-Identifier: GPL-3.0 + +/// @title The client incentives rewards logic + +/********************************* + * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ * + * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ * + * ░░░░░░█████████░░█████████░░░ * + * ░░░░░░██░░░████░░██░░░████░░░ * + * ░░██████░░░████████░░░████░░░ * + * ░░██░░██░░░████░░██░░░████░░░ * + * ░░██░░██░░░████░░██░░░████░░░ * + * ░░░░░░█████████░░█████████░░░ * + * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ * + * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ * + *********************************/ + +pragma solidity ^0.8.19; + +import { INounsDAOLogic } from '../interfaces/INounsDAOLogic.sol'; +import { INounsAuctionHouseV2 } from '../interfaces/INounsAuctionHouseV2.sol'; +import { NounsDAOTypes } from '../governance/NounsDAOInterfaces.sol'; +import { IERC20 } from '@openzeppelin/contracts/token/ERC20/IERC20.sol'; +import { UUPSUpgradeable } from '@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol'; +import { SafeERC20 } from '@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol'; +import { PausableUpgradeable } from '@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol'; +import { ClientRewardsMemoryMapping } from '../libs/ClientRewardsMemoryMapping.sol'; +import { GasRefund } from '../libs/GasRefund.sol'; +import { INounsClientTokenDescriptor } from './INounsClientTokenDescriptor.sol'; +import { INounsClientTokenTypes } from './INounsClientTokenTypes.sol'; +import { OwnableUpgradeable } from '@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol'; +import { ERC721Upgradeable } from '@openzeppelin/contracts-upgradeable/token/ERC721/ERC721Upgradeable.sol'; +import { SafeCast } from '@openzeppelin/contracts/utils/math/SafeCast.sol'; + +contract Rewards is + UUPSUpgradeable, + PausableUpgradeable, + OwnableUpgradeable, + ERC721Upgradeable, + INounsClientTokenTypes +{ + using SafeERC20 for IERC20; + using ClientRewardsMemoryMapping for ClientRewardsMemoryMapping.Mapping; + + error RewardsDisabled(); + error OnlyOwnerOrAdmin(); + error OnlyNFTOwner(); + error LastNounIdMustBeSettled(); + error LastNounIdMustBeHigher(); + + /** + * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + * EVENTS + * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + */ + + event ClientRegistered(uint32 indexed clientId, string name, string description); + event ClientUpdated(uint32 indexed clientId, string name, string description); + event ClientRewarded(uint32 indexed clientId, uint256 amount); + event ClientBalanceWithdrawal(uint32 indexed clientId, uint256 amount, address to); + event AuctionRewardsUpdated(uint256 firstAuctionId, uint256 lastAuctionId); + event ProposalRewardsUpdated( + uint32 firstProposalId, + uint32 lastProposalId, + uint256 firstAuctionIdForRevenue, + uint256 lastAuctionIdForRevenue, + uint256 auctionRevenue, + uint256 rewardPerProposal, + uint256 rewardPerVote + ); + event ClientApprovalSet(uint32 indexed clientId, bool approved); + event AuctionRewardsEnabled(uint32 nextAuctionIdToReward); + event AuctionRewardsDisabled(); + event ProposalRewardsEnabled(uint32 nextProposalIdToReward, uint32 nextProposalRewardFirstAuctionId); + event ProposalRewardsDisabled(); + + /** + * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + * IMMUTABLES + * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + */ + + /// @notice Nouns DAO proxy contract + INounsDAOLogic public immutable nounsDAO; + + /// @notice Nouns Auction House proxy contract + INounsAuctionHouseV2 public immutable auctionHouse; + + /** + * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + * STORAGE VARIABLES + * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + */ + + struct ProposalRewardParams { + /// @dev The minimum reward period for proposal updates if number of proposals is below `numProposalsEnoughForReward` + uint32 minimumRewardPeriod; + /// @dev The number of proposals required for an update before `minimumRewardPeriod` has passed + uint8 numProposalsEnoughForReward; + /// @dev How much bips out of the auction revenue during this period to use for rewarding proposal creation + uint16 proposalRewardBps; + /// @dev How much bips out of the auction revenue during this period to use for rewarding proposal voting + uint16 votingRewardBps; + /// @dev How many (in bips) FOR votes out of total votes are required for a proposal to be eligible for rewards + uint16 proposalEligibilityQuorumBps; + } + + struct AuctionRewardParams { + /// @dev How much bips out of auction revnue to use for rewarding auction bidding + uint16 auctionRewardBps; + /// @dev Minimum number of auctions between updates. Zero means 1 auction is enough. + uint8 minimumAuctionsBetweenUpdates; + } + + /// @custom:storage-location erc7201:nouns.rewards + struct RewardsStorage { + /// @dev The next client token id to be minted + uint32 nextTokenId; + /// @dev Flag controlling if auction rewards are enabled + bool auctionRewardsEnabled; + /// @dev Used for auction rewards state + uint32 nextAuctionIdToReward; + /// @dev Flag controlling if proposal rewards are enabled + bool proposalRewardsEnabled; + /// @dev Used for proposal rewards state + uint32 nextProposalIdToReward; + /// @dev The first auction id to consider for revenue tracking on the next proposal rewards update + uint32 nextProposalRewardFirstAuctionId; + /// @dev Last time the proposal rewards update was performed + uint40 lastProposalRewardsUpdate; + /// @dev Params for both proposal rewards + ProposalRewardParams proposalRewardParams; + /// @dev Params for auction rewards + AuctionRewardParams auctionRewardParams; + /// @dev An ETH pegged ERC20 token to use for rewarding + IERC20 ethToken; + /// @dev admin account able to pause/unpause the contract in case of a quick response is needed + address admin; + /// @dev client metadata per clientId, including rewards balances, name, description + mapping(uint32 clientId => ClientMetadata) _clientMetadata; + /// @dev The client NFT descriptor + address descriptor; + } + + /// @dev This is a ERC-7201 storage location, calculated using: + /// @dev keccak256(abi.encode(uint256(keccak256("nouns.rewards")) - 1)) & ~bytes32(uint256(0xff)); + bytes32 public constant RewardsStorageLocation = 0x9a06af3161ac5b0c3de4e6c981ab9d9f60b530386f5eaae00d541393fbecd700; + + function _getRewardsStorage() private pure returns (RewardsStorage storage $) { + assembly { + $.slot := RewardsStorageLocation + } + } + + /** + * @dev Reverts if called by any account other than the owner or admin. + */ + modifier onlyOwnerOrAdmin() { + RewardsStorage storage $ = _getRewardsStorage(); + if (!(owner() == _msgSender() || $.admin == _msgSender())) revert OnlyOwnerOrAdmin(); + _; + } + + constructor(address nounsDAO_, address auctionHouse_) initializer { + nounsDAO = INounsDAOLogic(nounsDAO_); + auctionHouse = INounsAuctionHouseV2(auctionHouse_); + } + + /** + * @param owner Address of the owner who has administration permissions as well as contract upgrade permissions + * @param admin_ Address which has permissions to pause and unpause + * @param ethToken_ An ETH pegged token (e.g. WETH) which will be used for rewards and gas refunds + * @param descriptor_ Address of a INounsClientTokenDescriptor contract to provide tokenURI for the NFTs + */ + function initialize(address owner, address admin_, address ethToken_, address descriptor_) public initializer { + __Pausable_init_unchained(); + __ERC721_init('Nouns Client Token', 'NOUNSCLIENT'); + + RewardsStorage storage $ = _getRewardsStorage(); + $.nextTokenId = 1; + + _transferOwnership(owner); + $.admin = admin_; + $.ethToken = IERC20(ethToken_); + $.descriptor = descriptor_; + } + + /** + * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + * PUBLIC WRITE + * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + */ + + /** + * @notice Register a client, mints an NFT and assigns a clientId + * @param name a short name identifying the client + * @param description a longer description for the client, ideally a URL + * @return uint32 the newly assigned clientId + */ + function registerClient(string calldata name, string calldata description) external whenNotPaused returns (uint32) { + RewardsStorage storage $ = _getRewardsStorage(); + + uint32 tokenId = $.nextTokenId; + $.nextTokenId = tokenId + 1; + _mint(msg.sender, tokenId); + + ClientMetadata storage md = $._clientMetadata[tokenId]; + md.name = name; + md.description = description; + + emit ClientRegistered(tokenId, name, description); + + return tokenId; + } + + /** + * @notice Update the metadata of a client + * @dev Only the owner of the client token can update the metadata. + * @param tokenId The token ID of the client + * @param name The new name of the client + * @param description The new description of the client + */ + function updateClientMetadata(uint32 tokenId, string calldata name, string calldata description) external { + RewardsStorage storage $ = _getRewardsStorage(); + + if (ownerOf(tokenId) != msg.sender) revert OnlyNFTOwner(); + ClientMetadata storage md = $._clientMetadata[tokenId]; + md.name = name; + md.description = description; + + emit ClientUpdated(tokenId, name, description); + } + + /** + * @notice Distribute rewards for auction bidding since the last update until auction with id `lastNounId` + * If an auction's winning bid was called with a clientId, that client will be reward with `params.auctionRewardBps` + * bips of the auction's settlement amount. + * At least `minimumAuctionsBetweenUpdates` must happen between updates. + * Gas spent is refunded in `ethToken`. + * @param lastNounId the last auction id to reward client for. must be already settled. + * @dev Gas is refunded if at least one auction was rewarded + */ + function updateRewardsForAuctions(uint32 lastNounId) public whenNotPaused { + uint256 startGas = gasleft(); + RewardsStorage storage $ = _getRewardsStorage(); + if (!$.auctionRewardsEnabled) revert RewardsDisabled(); + + bool sawValidClientId = false; + uint256 nextAuctionIdToReward_ = $.nextAuctionIdToReward; + if (lastNounId < nextAuctionIdToReward_ + $.auctionRewardParams.minimumAuctionsBetweenUpdates) + revert LastNounIdMustBeHigher(); + + $.nextAuctionIdToReward = lastNounId + 1; + + INounsAuctionHouseV2.Settlement[] memory settlements = auctionHouse.getSettlements( + nextAuctionIdToReward_, + lastNounId + 1, + true + ); + INounsAuctionHouseV2.Settlement memory lastSettlement = settlements[settlements.length - 1]; + if (!(lastSettlement.nounId == lastNounId && lastSettlement.blockTimestamp > 1)) + revert LastNounIdMustBeSettled(); + + uint32 maxClientId = nextTokenId() - 1; + ClientRewardsMemoryMapping.Mapping memory m = ClientRewardsMemoryMapping.createMapping({ + maxClientId: maxClientId + }); + + for (uint256 i; i < settlements.length; ++i) { + INounsAuctionHouseV2.Settlement memory settlement = settlements[i]; + if (settlement.clientId != 0 && settlement.clientId <= maxClientId) { + sawValidClientId = true; + m.inc(settlement.clientId, settlement.amount); + } + } + + uint16 auctionRewardBps = $.auctionRewardParams.auctionRewardBps; + uint256 numValues = m.numValues(); + for (uint32 i = 0; i < numValues; ++i) { + ClientRewardsMemoryMapping.ClientBalance memory cb = m.getValue(i); + uint256 reward = (cb.balance * auctionRewardBps) / 10_000; + $._clientMetadata[cb.clientId].rewarded += SafeCast.toUint96(reward); + + emit ClientRewarded(cb.clientId, reward); + } + + emit AuctionRewardsUpdated(nextAuctionIdToReward_, lastNounId); + + if (sawValidClientId) { + // refund gas only if we're actually rewarding a client, not just moving the pointer + GasRefund.refundGas($.ethToken, startGas); + } + } + + /// @dev struct used to avoid stack-too-deep errors + struct Temp { + uint32 maxClientId; + uint256 numEligibleVotes; + uint256 rewardPerProposal; + uint256 rewardPerVote; + uint256 proposalRewardForPeriod; + uint256 votingRewardForPeriod; + uint256 firstAuctionIdForRevenue; + NounsDAOTypes.ProposalForRewards lastProposal; + } + + /** + * @notice Distribute rewards for proposal creation and voting from the last update until `lastProposalId`. + * A proposal is eligible for rewards if it wasn't canceled and for-votes/total-votes >= params.proposalEligibilityQuorumBps. + * Rewards are calculated by the auctions revenue during the period between the creation time of last processed + * eligible proposal in until the current last eligible proposal with id <= `lastProposalId`. + * One of two conditions must be true in order for rewards to be distributed: + * 1. There are at least `numProposalsEnoughForReward` proposals in this update + * 2. At least `minimumRewardPeriod` time has passed since the last update until the creation time of the last + * eligible proposal in this update. + * Gas spent is refunded in `ethToken`. + * @param lastProposalId id of the last proposal to include in the rewards distribution. all proposals up to and + * including this id must have ended voting. + * @param votingClientIds array of sorted client ids that were used to vote on the eligible proposals in + * this rewards distribution. Reverts if it contains duplicates. Reverts if it's not sorted. Reverts if a clientId + * had zero votes on all eligible proposals from this update. + * You may use `getVotingClientIds` as a convenience function to get the correct `votingClientIds`. + */ + function updateRewardsForProposalWritingAndVoting( + uint32 lastProposalId, + uint32[] calldata votingClientIds + ) public whenNotPaused { + uint256 startGas = gasleft(); + RewardsStorage storage $ = _getRewardsStorage(); + if (!$.proposalRewardsEnabled) revert RewardsDisabled(); + + Temp memory t; + + t.maxClientId = nextTokenId() - 1; + uint32 nextProposalIdToReward_ = $.nextProposalIdToReward; + + require( + (lastProposalId <= nounsDAO.proposalCount()) && (lastProposalId >= nextProposalIdToReward_), + 'bad lastProposalId' + ); + require(isSortedAndNoDuplicates(votingClientIds), 'must be sorted & unique'); + + NounsDAOTypes.ProposalForRewards[] memory proposals = nounsDAO.proposalDataForRewards({ + firstProposalId: nextProposalIdToReward_, + lastProposalId: lastProposalId, + proposalEligibilityQuorumBps: $.proposalRewardParams.proposalEligibilityQuorumBps, + excludeCanceled: true, + requireVotingEnded: true, + votingClientIds: votingClientIds + }); + require(proposals.length > 0, 'at least one eligible proposal'); + $.nextProposalIdToReward = lastProposalId + 1; + + t.lastProposal = proposals[proposals.length - 1]; + + t.firstAuctionIdForRevenue = $.nextProposalRewardFirstAuctionId; + (uint256 auctionRevenue, uint256 lastAuctionIdForRevenue) = getAuctionRevenue({ + firstNounId: t.firstAuctionIdForRevenue, + endTimestamp: t.lastProposal.creationTimestamp + }); + $.nextProposalRewardFirstAuctionId = uint32(lastAuctionIdForRevenue) + 1; + + require(auctionRevenue > 0, 'auctionRevenue must be > 0'); + + t.proposalRewardForPeriod = (auctionRevenue * $.proposalRewardParams.proposalRewardBps) / 10_000; + t.votingRewardForPeriod = (auctionRevenue * $.proposalRewardParams.votingRewardBps) / 10_000; + + //// First loop over the proposals: + //// 1. Count the number of votes in eligible proposals. + + for (uint256 i; i < proposals.length; ++i) { + uint256 votesInProposal = proposals[i].forVotes + proposals[i].againstVotes + proposals[i].abstainVotes; + t.numEligibleVotes += votesInProposal; + } + + //// Check that distribution is allowed: + //// 1. One of the two conditions must be true: + //// 1.a. Number of eligible proposals is at least `numProposalsEnoughForReward`. + //// 1.b. At least `minimumRewardPeriod` seconds have passed since the last update. + + if (proposals.length < $.proposalRewardParams.numProposalsEnoughForReward) { + require( + t.lastProposal.creationTimestamp > + $.lastProposalRewardsUpdate + $.proposalRewardParams.minimumRewardPeriod, + 'not enough time passed' + ); + } + $.lastProposalRewardsUpdate = uint40(t.lastProposal.creationTimestamp); + + // Calculate the reward per proposal and per vote + t.rewardPerProposal = t.proposalRewardForPeriod / proposals.length; + t.rewardPerVote = t.votingRewardForPeriod / t.numEligibleVotes; + + emit ProposalRewardsUpdated( + nextProposalIdToReward_, + lastProposalId, + t.firstAuctionIdForRevenue, + lastAuctionIdForRevenue, + auctionRevenue, + t.rewardPerProposal, + t.rewardPerVote + ); + + //// Second loop over the proposals: + //// 1. Reward proposal's clientId. + //// 2. Reward the clientIds that faciliated voting. + //// 3. Make sure all voting clientIds were included. This is meant to avoid griefing. Otherwises one could pass + //// a large array of votingClientIds, spend a lot of gas, and have that gas refunded. + + ClientRewardsMemoryMapping.Mapping memory m = ClientRewardsMemoryMapping.createMapping({ + maxClientId: t.maxClientId + }); + bool[] memory didClientIdHaveVotes = new bool[](votingClientIds.length); + + for (uint256 i; i < proposals.length; ++i) { + uint32 clientId = proposals[i].clientId; + if (clientId != 0 && clientId <= t.maxClientId) { + m.inc(clientId, t.rewardPerProposal); + } + + uint256 votesInProposal; + NounsDAOTypes.ClientVoteData[] memory voteData = proposals[i].voteData; + for (uint256 j; j < votingClientIds.length; ++j) { + clientId = votingClientIds[j]; + uint256 votes = voteData[j].votes; + didClientIdHaveVotes[j] = didClientIdHaveVotes[j] || votes > 0; + if (clientId != 0 && clientId <= t.maxClientId) { + m.inc(clientId, votes * t.rewardPerVote); + } + votesInProposal += votes; + } + require( + votesInProposal == proposals[i].forVotes + proposals[i].againstVotes + proposals[i].abstainVotes, + 'not all votes accounted' + ); + } + + for (uint256 i = 0; i < didClientIdHaveVotes.length; ++i) { + require(didClientIdHaveVotes[i], 'all clientId must have votes'); + } + + uint256 numValues = m.numValues(); + for (uint32 i = 0; i < numValues; ++i) { + ClientRewardsMemoryMapping.ClientBalance memory cb = m.getValue(i); + $._clientMetadata[cb.clientId].rewarded += SafeCast.toUint96(cb.balance); + emit ClientRewarded(cb.clientId, cb.balance); + } + + GasRefund.refundGas($.ethToken, startGas); + } + + /** + * @notice Withdraws the balance of a client + * @dev The caller must be the owner of the NFT with id `clientId` and the client must be approved by the DAO. + * @param clientId Which client balance to withdraw + * @param to the address to withdraw to + * @param amount amount to withdraw + */ + function withdrawClientBalance(uint32 clientId, address to, uint96 amount) public whenNotPaused { + RewardsStorage storage $ = _getRewardsStorage(); + ClientMetadata storage md = $._clientMetadata[clientId]; + + if (ownerOf(clientId) != msg.sender) revert OnlyNFTOwner(); + require(md.approved, 'not approved'); + + uint96 withdrawnCache = md.withdrawn; + require(amount <= md.rewarded - withdrawnCache, 'amount too large'); + + md.withdrawn = withdrawnCache + amount; + + emit ClientBalanceWithdrawal(clientId, amount, to); + + $.ethToken.safeTransfer(to, amount); + } + + /** + * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + * PUBLIC READ + * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + */ + + /** + * @notice Returns the withdrawable balance of client with id `clientId` + */ + function clientBalance(uint32 clientId) public view returns (uint96) { + RewardsStorage storage $ = _getRewardsStorage(); + ClientMetadata storage md = $._clientMetadata[clientId]; + return md.rewarded - md.withdrawn; + } + + /** + * @notice Returns the clientIds that are needed to be passed as a parameter to updateRewardsForProposalWritingAndVoting + * @dev This is not meant to be called onchain because it may be very gas intensive. + */ + function getVotingClientIds(uint32 lastProposalId) public view returns (uint32[] memory) { + RewardsStorage storage $ = _getRewardsStorage(); + + uint256 numClientIds = nextTokenId(); + uint32[] memory allClientIds = new uint32[](numClientIds); + for (uint32 i; i < numClientIds; ++i) { + allClientIds[i] = i; + } + NounsDAOTypes.ProposalForRewards[] memory proposals = nounsDAO.proposalDataForRewards({ + firstProposalId: $.nextProposalIdToReward, + lastProposalId: lastProposalId, + proposalEligibilityQuorumBps: $.proposalRewardParams.proposalEligibilityQuorumBps, + excludeCanceled: true, + requireVotingEnded: true, + votingClientIds: allClientIds + }); + + uint32[] memory sumVotes = new uint32[](numClientIds); + for (uint256 i; i < proposals.length; ++i) { + for (uint256 j; j < numClientIds; ++j) { + sumVotes[j] += proposals[i].voteData[j].votes; + } + } + + uint256 idx; + uint32[] memory nonZeroClientIds = new uint32[](numClientIds); + for (uint32 i; i < numClientIds; ++i) { + if (sumVotes[i] > 0) nonZeroClientIds[idx++] = i; + } + + assembly { + mstore(nonZeroClientIds, idx) + } + + return nonZeroClientIds; + } + + /** + * @notice Returns the sum of revenue via auctions from auctioning noun with id `firstNounId` until timestamp of `endTimestamp + */ + function getAuctionRevenue( + uint256 firstNounId, + uint256 endTimestamp + ) public view returns (uint256 sumRevenue, uint256 lastAuctionId) { + INounsAuctionHouseV2.Settlement[] memory s = auctionHouse.getSettlementsFromIdtoTimestamp( + firstNounId, + endTimestamp, + true + ); + sumRevenue = sumAuctions(s); + lastAuctionId = s[s.length - 1].nounId; + } + + /** + * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + * PUBLIC READ - STORAGE GETTERS + * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + */ + + function nextAuctionIdToReward() public view returns (uint256) { + return _getRewardsStorage().nextAuctionIdToReward; + } + + function nextProposalIdToReward() public view returns (uint32) { + return _getRewardsStorage().nextProposalIdToReward; + } + + function nextProposalRewardFirstAuctionId() public view returns (uint256) { + return _getRewardsStorage().nextProposalRewardFirstAuctionId; + } + + function lastProposalRewardsUpdate() public view returns (uint256) { + return _getRewardsStorage().lastProposalRewardsUpdate; + } + + function getAuctionRewardParams() public view returns (AuctionRewardParams memory) { + return _getRewardsStorage().auctionRewardParams; + } + + function getProposalRewardParams() public view returns (ProposalRewardParams memory) { + return _getRewardsStorage().proposalRewardParams; + } + + function auctionRewardsEnabled() public view returns (bool) { + return _getRewardsStorage().auctionRewardsEnabled; + } + + function proposalRewardsEnabled() public view returns (bool) { + return _getRewardsStorage().proposalRewardsEnabled; + } + + function ethToken() public view returns (IERC20) { + return _getRewardsStorage().ethToken; + } + + function admin() public view returns (address) { + return _getRewardsStorage().admin; + } + + /** + * @notice Get the metadata of a client + */ + function clientMetadata(uint32 tokenId) public view returns (ClientMetadata memory) { + return _getRewardsStorage()._clientMetadata[tokenId]; + } + + /** + * @notice Get the URI of a client token + */ + function tokenURI(uint256 tokenId) public view override returns (string memory) { + RewardsStorage storage $ = _getRewardsStorage(); + return INounsClientTokenDescriptor($.descriptor).tokenURI(tokenId, $._clientMetadata[uint32(tokenId)]); + } + + /** + * @notice Get the descriptor for the client token + */ + function descriptor() public view returns (address) { + return _getRewardsStorage().descriptor; + } + + /** + * @notice Get the next token ID + */ + function nextTokenId() public view returns (uint32) { + return _getRewardsStorage().nextTokenId; + } + + /** + * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + * ADMIN + * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + */ + + /** + * @notice Set whether the client is approved to withdraw their reward balance. + * Anyone can mint a client NFT and start earning rewards, but only approved clients can withdraw. + * This way the DAO helps mitigate abuse. + * @dev Only `owner` can call this function + */ + function setClientApproval(uint32 clientId, bool approved) public onlyOwner { + RewardsStorage storage $ = _getRewardsStorage(); + $._clientMetadata[clientId].approved = approved; + emit ClientApprovalSet(clientId, approved); + } + + /** + * @notice Updates the auction rewards params + * @dev Only `owner` can call this function + */ + function setAuctionRewardParams(AuctionRewardParams calldata newParams) public onlyOwner { + _getRewardsStorage().auctionRewardParams = newParams; + } + + /** + * @notice Enables auction rewards and sets the next auction id to reward to be the current noun on auction + * @dev Only `owner` can call this function + */ + function enableAuctionRewards() public onlyOwner { + RewardsStorage storage $ = _getRewardsStorage(); + uint32 nextAuctionIdToReward = SafeCast.toUint32(auctionHouse.auction().nounId); + $.nextAuctionIdToReward = nextAuctionIdToReward; + $.auctionRewardsEnabled = true; + + emit AuctionRewardsEnabled(nextAuctionIdToReward); + } + + /** + * @notice Disables auction rewards + * @dev Only `owner` can call this function + */ + function disableAuctionRewards() public onlyOwner { + _getRewardsStorage().auctionRewardsEnabled = false; + + emit AuctionRewardsDisabled(); + } + + /** + * @notice Updates the proposal rewards params + * @dev Only `owner` can call this function + */ + function setProposalRewardParams(ProposalRewardParams calldata newParams) public onlyOwner { + _getRewardsStorage().proposalRewardParams = newParams; + } + + /** + * @notice Enables proposal rewards and sets the next proposal ID to reward to be the next proposal to be created. + * The first auction ID to be considered for revenue calculation is set to be the current noun in auction. + * @dev Only `owner` can call this function + */ + function enableProposalRewards() public onlyOwner { + RewardsStorage storage $ = _getRewardsStorage(); + uint32 nextProposalIdToReward = SafeCast.toUint32(nounsDAO.proposalCount() + 1); + uint32 nextProposalRewardFirstAuctionId = SafeCast.toUint32(auctionHouse.auction().nounId); + $.nextProposalIdToReward = nextProposalIdToReward; + $.nextProposalRewardFirstAuctionId = nextProposalRewardFirstAuctionId; + $.lastProposalRewardsUpdate = uint40(block.timestamp); + $.proposalRewardsEnabled = true; + + emit ProposalRewardsEnabled(nextProposalIdToReward, nextProposalRewardFirstAuctionId); + } + + /** + * @notice Disables proposal rewards + * @dev Only `owner` can call this function + */ + function disableProposalRewards() public onlyOwner { + _getRewardsStorage().proposalRewardsEnabled = false; + + emit ProposalRewardsDisabled(); + } + + /** + * @dev Only `owner` can call this function + */ + function setAdmin(address newAdmin) public onlyOwner { + _getRewardsStorage().admin = newAdmin; + } + + /** + * @dev Only `owner` can call this function + */ + function setETHToken(address newToken) public onlyOwner { + _getRewardsStorage().ethToken = IERC20(newToken); + } + + /** + * @notice Withdraws any ERC20 token held by the contract + * @param token Address of ERC20 token + * @param to Address to send tokens to + * @param amount Amount of tokens to withdraw + * @dev Only `owner` can call this function + */ + function withdrawToken(address token, address to, uint256 amount) public onlyOwner { + IERC20(token).safeTransfer(to, amount); + } + + /** + * @notice Pauses reward distributes, client registration and withdrawals + * @dev Only `owner` or `admin` can call this function + */ + function pause() public onlyOwnerOrAdmin { + _pause(); + } + + /** + * @notice Unpauses reward distributes, client registration and withdrawals + * @dev Only `owner` or `admin` can call this function + */ + function unpause() public onlyOwnerOrAdmin { + _unpause(); + } + + /** + * @notice Set the descriptor for the client token + * @dev Only `owner` or `admin` can call this function + */ + function setDescriptor(address descriptor_) public onlyOwnerOrAdmin { + _getRewardsStorage().descriptor = descriptor_; + } + + /** + * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + * INTERNAL + * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + */ + + function sumAuctions(INounsAuctionHouseV2.Settlement[] memory s) internal pure returns (uint256 sum) { + for (uint256 i = 0; i < s.length; ++i) { + sum += s[i].amount; + } + } + + /** + * @dev returns true if ids is an array of increasing unique values, i.e. sorted ascending and no duplicates + */ + function isSortedAndNoDuplicates(uint32[] memory ids) internal pure returns (bool) { + uint256 len = ids.length; + uint32 prevValue = ids[0]; + for (uint256 i = 1; i < len; ++i) { + uint32 nextValue = ids[i]; + if (nextValue <= prevValue) return false; + prevValue = nextValue; + } + return true; + } + + /** + * Only `owner` can perform an upgrade + */ + function _authorizeUpgrade(address) internal view override onlyOwner {} +} diff --git a/packages/nouns-contracts/contracts/client-incentives/RewardsProxy.sol b/packages/nouns-contracts/contracts/client-incentives/RewardsProxy.sol new file mode 100644 index 0000000000..cecf5ab050 --- /dev/null +++ b/packages/nouns-contracts/contracts/client-incentives/RewardsProxy.sol @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: GPL-3.0 + +/// @title The Client Incentives Rewards proxy + +/********************************* + * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ * + * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ * + * ░░░░░░█████████░░█████████░░░ * + * ░░░░░░██░░░████░░██░░░████░░░ * + * ░░██████░░░████████░░░████░░░ * + * ░░██░░██░░░████░░██░░░████░░░ * + * ░░██░░██░░░████░░██░░░████░░░ * + * ░░░░░░█████████░░█████████░░░ * + * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ * + * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ * + *********************************/ + +pragma solidity ^0.8.19; + +import { ERC1967Proxy } from '@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol'; + +contract RewardsProxy is ERC1967Proxy { + constructor(address _logic, bytes memory _data) payable ERC1967Proxy(_logic, _data) {} +} diff --git a/packages/nouns-contracts/contracts/governance/NounsDAOV3Admin.sol b/packages/nouns-contracts/contracts/governance/NounsDAOAdmin.sol similarity index 67% rename from packages/nouns-contracts/contracts/governance/NounsDAOV3Admin.sol rename to packages/nouns-contracts/contracts/governance/NounsDAOAdmin.sol index 6102986b77..367ec22f19 100644 --- a/packages/nouns-contracts/contracts/governance/NounsDAOV3Admin.sol +++ b/packages/nouns-contracts/contracts/governance/NounsDAOAdmin.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-3.0 -/// @title Library for NounsDAOLogicV3 contract containing admin related functions +/// @title Library for Nouns DAO Logic containing admin related functions /********************************* * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ * @@ -18,10 +18,10 @@ pragma solidity ^0.8.19; import './NounsDAOInterfaces.sol'; -import { NounsDAOV3DynamicQuorum } from './NounsDAOV3DynamicQuorum.sol'; +import { NounsDAODynamicQuorum } from './NounsDAODynamicQuorum.sol'; -library NounsDAOV3Admin { - using NounsDAOV3DynamicQuorum for NounsDAOStorageV3.StorageV3; +library NounsDAOAdmin { + using NounsDAODynamicQuorum for NounsDAOTypes.Storage; error AdminOnly(); error VetoerOnly(); @@ -84,12 +84,6 @@ library NounsDAOV3Admin { /// @notice Emitted when admin withdraws the DAO's balance. event Withdraw(uint256 amount, bool sent); - /// @notice Emitted when the proposal id at which vote snapshot block changes is set - event VoteSnapshotBlockSwitchProposalIdSet( - uint256 oldVoteSnapshotBlockSwitchProposalId, - uint256 newVoteSnapshotBlockSwitchProposalId - ); - /// @notice Emitted when the fork DAO deployer is set event ForkDAODeployerSet(address oldForkDAODeployer, address newForkDAODeployer); @@ -147,8 +141,8 @@ library NounsDAOV3Admin { /// @notice Upper bound for proposal updatable period duration in blocks. uint256 public constant MAX_UPDATABLE_PERIOD_BLOCKS = 7 days / 12; - modifier onlyAdmin(NounsDAOStorageV3.StorageV3 storage ds) { - if (msg.sender != ds.admin) { + modifier onlyAdmin() { + if (msg.sender != ds().admin) { revert AdminOnly(); } _; @@ -159,13 +153,13 @@ library NounsDAOV3Admin { * voters time to make sense of proposals, e.g. 21,600 blocks which should be at least 3 days. * @param newVotingDelay new voting delay, in blocks */ - function _setVotingDelay(NounsDAOStorageV3.StorageV3 storage ds, uint256 newVotingDelay) external onlyAdmin(ds) { + function _setVotingDelay(uint256 newVotingDelay) external onlyAdmin { require( newVotingDelay >= MIN_VOTING_DELAY_BLOCKS && newVotingDelay <= MAX_VOTING_DELAY_BLOCKS, 'NounsDAO::_setVotingDelay: invalid voting delay' ); - uint256 oldVotingDelay = ds.votingDelay; - ds.votingDelay = newVotingDelay; + uint256 oldVotingDelay = ds().votingDelay; + ds().votingDelay = newVotingDelay; emit VotingDelaySet(oldVotingDelay, newVotingDelay); } @@ -174,13 +168,13 @@ library NounsDAOV3Admin { * @notice Admin function for setting the voting period * @param newVotingPeriod new voting period, in blocks */ - function _setVotingPeriod(NounsDAOStorageV3.StorageV3 storage ds, uint256 newVotingPeriod) external onlyAdmin(ds) { + function _setVotingPeriod(uint256 newVotingPeriod) external onlyAdmin { require( newVotingPeriod >= MIN_VOTING_PERIOD_BLOCKS && newVotingPeriod <= MAX_VOTING_PERIOD_BLOCKS, 'NounsDAO::_setVotingPeriod: invalid voting period' ); - uint256 oldVotingPeriod = ds.votingPeriod; - ds.votingPeriod = newVotingPeriod; + uint256 oldVotingPeriod = ds().votingPeriod; + ds().votingPeriod = newVotingPeriod; emit VotingPeriodSet(oldVotingPeriod, newVotingPeriod); } @@ -190,17 +184,14 @@ library NounsDAOV3Admin { * @dev newProposalThresholdBPS must be in [`MIN_PROPOSAL_THRESHOLD_BPS`,`MAX_PROPOSAL_THRESHOLD_BPS`] * @param newProposalThresholdBPS new proposal threshold */ - function _setProposalThresholdBPS(NounsDAOStorageV3.StorageV3 storage ds, uint256 newProposalThresholdBPS) - external - onlyAdmin(ds) - { + function _setProposalThresholdBPS(uint256 newProposalThresholdBPS) external onlyAdmin { require( newProposalThresholdBPS >= MIN_PROPOSAL_THRESHOLD_BPS && newProposalThresholdBPS <= MAX_PROPOSAL_THRESHOLD_BPS, 'NounsDAO::_setProposalThreshold: invalid proposal threshold bps' ); - uint256 oldProposalThresholdBPS = ds.proposalThresholdBPS; - ds.proposalThresholdBPS = newProposalThresholdBPS; + uint256 oldProposalThresholdBPS = ds().proposalThresholdBPS; + ds().proposalThresholdBPS = newProposalThresholdBPS; emit ProposalThresholdBPSSet(oldProposalThresholdBPS, newProposalThresholdBPS); } @@ -209,15 +200,12 @@ library NounsDAOV3Admin { * @notice Admin function for setting the objection period duration * @param newObjectionPeriodDurationInBlocks new objection period duration, in blocks */ - function _setObjectionPeriodDurationInBlocks( - NounsDAOStorageV3.StorageV3 storage ds, - uint32 newObjectionPeriodDurationInBlocks - ) external onlyAdmin(ds) { + function _setObjectionPeriodDurationInBlocks(uint32 newObjectionPeriodDurationInBlocks) external onlyAdmin { if (newObjectionPeriodDurationInBlocks > MAX_OBJECTION_PERIOD_BLOCKS) revert InvalidObjectionPeriodDurationInBlocks(); - uint32 oldObjectionPeriodDurationInBlocks = ds.objectionPeriodDurationInBlocks; - ds.objectionPeriodDurationInBlocks = newObjectionPeriodDurationInBlocks; + uint32 oldObjectionPeriodDurationInBlocks = ds().objectionPeriodDurationInBlocks; + ds().objectionPeriodDurationInBlocks = newObjectionPeriodDurationInBlocks; emit ObjectionPeriodDurationSet(oldObjectionPeriodDurationInBlocks, newObjectionPeriodDurationInBlocks); } @@ -226,12 +214,9 @@ library NounsDAOV3Admin { * @notice Admin function for setting the objection period last minute window * @param newLastMinuteWindowInBlocks new objection period last minute window, in blocks */ - function _setLastMinuteWindowInBlocks(NounsDAOStorageV3.StorageV3 storage ds, uint32 newLastMinuteWindowInBlocks) - external - onlyAdmin(ds) - { - uint32 oldLastMinuteWindowInBlocks = ds.lastMinuteWindowInBlocks; - ds.lastMinuteWindowInBlocks = newLastMinuteWindowInBlocks; + function _setLastMinuteWindowInBlocks(uint32 newLastMinuteWindowInBlocks) external onlyAdmin { + uint32 oldLastMinuteWindowInBlocks = ds().lastMinuteWindowInBlocks; + ds().lastMinuteWindowInBlocks = newLastMinuteWindowInBlocks; emit LastMinuteWindowSet(oldLastMinuteWindowInBlocks, newLastMinuteWindowInBlocks); } @@ -240,15 +225,12 @@ library NounsDAOV3Admin { * @notice Admin function for setting the proposal updatable period * @param newProposalUpdatablePeriodInBlocks the new proposal updatable period, in blocks */ - function _setProposalUpdatablePeriodInBlocks( - NounsDAOStorageV3.StorageV3 storage ds, - uint32 newProposalUpdatablePeriodInBlocks - ) external onlyAdmin(ds) { + function _setProposalUpdatablePeriodInBlocks(uint32 newProposalUpdatablePeriodInBlocks) external onlyAdmin { if (newProposalUpdatablePeriodInBlocks > MAX_UPDATABLE_PERIOD_BLOCKS) revert InvalidProposalUpdatablePeriodInBlocks(); - uint32 oldProposalUpdatablePeriodInBlocks = ds.proposalUpdatablePeriodInBlocks; - ds.proposalUpdatablePeriodInBlocks = newProposalUpdatablePeriodInBlocks; + uint32 oldProposalUpdatablePeriodInBlocks = ds().proposalUpdatablePeriodInBlocks; + ds().proposalUpdatablePeriodInBlocks = newProposalUpdatablePeriodInBlocks; emit ProposalUpdatablePeriodSet(oldProposalUpdatablePeriodInBlocks, newProposalUpdatablePeriodInBlocks); } @@ -258,12 +240,12 @@ library NounsDAOV3Admin { * @dev Admin function to begin change of admin. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer. * @param newPendingAdmin New pending admin. */ - function _setPendingAdmin(NounsDAOStorageV3.StorageV3 storage ds, address newPendingAdmin) external onlyAdmin(ds) { + function _setPendingAdmin(address newPendingAdmin) external onlyAdmin { // Save current value, if any, for inclusion in log - address oldPendingAdmin = ds.pendingAdmin; + address oldPendingAdmin = ds().pendingAdmin; // Store pendingAdmin with value newPendingAdmin - ds.pendingAdmin = newPendingAdmin; + ds().pendingAdmin = newPendingAdmin; // Emit NewPendingAdmin(oldPendingAdmin, newPendingAdmin) emit NewPendingAdmin(oldPendingAdmin, newPendingAdmin); @@ -273,24 +255,24 @@ library NounsDAOV3Admin { * @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(NounsDAOStorageV3.StorageV3 storage ds) external { + function _acceptAdmin() external { // Check caller is pendingAdmin and pendingAdmin ≠ address(0) require( - msg.sender == ds.pendingAdmin && msg.sender != address(0), + msg.sender == ds().pendingAdmin && msg.sender != address(0), 'NounsDAO::_acceptAdmin: pending admin only' ); // Save current values for inclusion in log - address oldAdmin = ds.admin; - address oldPendingAdmin = ds.pendingAdmin; + address oldAdmin = ds().admin; + address oldPendingAdmin = ds().pendingAdmin; // Store admin with value pendingAdmin - ds.admin = ds.pendingAdmin; + ds().admin = ds().pendingAdmin; // Clear the pending value - ds.pendingAdmin = address(0); + ds().pendingAdmin = address(0); - emit NewAdmin(oldAdmin, ds.admin); + emit NewAdmin(oldAdmin, ds().admin); emit NewPendingAdmin(oldPendingAdmin, address(0)); } @@ -298,48 +280,48 @@ library NounsDAOV3Admin { * @notice Begins transition of vetoer. The newPendingVetoer must call _acceptVetoer to finalize the transfer. * @param newPendingVetoer New Pending Vetoer */ - function _setPendingVetoer(NounsDAOStorageV3.StorageV3 storage ds, address newPendingVetoer) public { - if (msg.sender != ds.vetoer) { + function _setPendingVetoer(address newPendingVetoer) public { + if (msg.sender != ds().vetoer) { revert VetoerOnly(); } - emit NewPendingVetoer(ds.pendingVetoer, newPendingVetoer); + emit NewPendingVetoer(ds().pendingVetoer, newPendingVetoer); - ds.pendingVetoer = newPendingVetoer; + ds().pendingVetoer = newPendingVetoer; } /** * @notice Called by the pendingVetoer to accept role and update vetoer */ - function _acceptVetoer(NounsDAOStorageV3.StorageV3 storage ds) external { - if (msg.sender != ds.pendingVetoer) { + function _acceptVetoer() external { + if (msg.sender != ds().pendingVetoer) { revert PendingVetoerOnly(); } // Update vetoer - emit NewVetoer(ds.vetoer, ds.pendingVetoer); - ds.vetoer = ds.pendingVetoer; + emit NewVetoer(ds().vetoer, ds().pendingVetoer); + ds().vetoer = ds().pendingVetoer; // Clear the pending value - emit NewPendingVetoer(ds.pendingVetoer, address(0)); - ds.pendingVetoer = address(0); + emit NewPendingVetoer(ds().pendingVetoer, address(0)); + ds().pendingVetoer = address(0); } /** * @notice Burns veto priviledges * @dev Vetoer function destroying veto power forever */ - function _burnVetoPower(NounsDAOStorageV3.StorageV3 storage ds) public { + function _burnVetoPower() public { // Check caller is vetoer - require(msg.sender == ds.vetoer, 'NounsDAO::_burnVetoPower: vetoer only'); + require(msg.sender == ds().vetoer, 'NounsDAO::_burnVetoPower: vetoer only'); // Update vetoer to 0x0 - emit NewVetoer(ds.vetoer, address(0)); - ds.vetoer = address(0); + emit NewVetoer(ds().vetoer, address(0)); + ds().vetoer = address(0); // Clear the pending value - emit NewPendingVetoer(ds.pendingVetoer, address(0)); - ds.pendingVetoer = address(0); + emit NewPendingVetoer(ds().pendingVetoer, address(0)); + ds().pendingVetoer = address(0); } /** @@ -348,11 +330,8 @@ library NounsDAOV3Admin { * 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(NounsDAOStorageV3.StorageV3 storage ds, uint16 newMinQuorumVotesBPS) - external - onlyAdmin(ds) - { - NounsDAOStorageV3.DynamicQuorumParams memory params = ds.getDynamicQuorumParamsAt(block.number); + function _setMinQuorumVotesBPS(uint16 newMinQuorumVotesBPS) external onlyAdmin { + NounsDAOTypes.DynamicQuorumParams memory params = ds().getDynamicQuorumParamsAt(block.number); require( newMinQuorumVotesBPS >= MIN_QUORUM_VOTES_BPS_LOWER_BOUND && @@ -367,7 +346,7 @@ library NounsDAOV3Admin { uint16 oldMinQuorumVotesBPS = params.minQuorumVotesBPS; params.minQuorumVotesBPS = newMinQuorumVotesBPS; - _writeQuorumParamsCheckpoint(ds, params); + _writeQuorumParamsCheckpoint(params); emit MinQuorumVotesBPSSet(oldMinQuorumVotesBPS, newMinQuorumVotesBPS); } @@ -378,11 +357,8 @@ library NounsDAOV3Admin { * Must be lower than `MAX_QUORUM_VOTES_BPS_UPPER_BOUND` * Must be higher than or equal to minQuorumVotesBPS */ - function _setMaxQuorumVotesBPS(NounsDAOStorageV3.StorageV3 storage ds, uint16 newMaxQuorumVotesBPS) - external - onlyAdmin(ds) - { - NounsDAOStorageV3.DynamicQuorumParams memory params = ds.getDynamicQuorumParamsAt(block.number); + function _setMaxQuorumVotesBPS(uint16 newMaxQuorumVotesBPS) external onlyAdmin { + NounsDAOTypes.DynamicQuorumParams memory params = ds().getDynamicQuorumParamsAt(block.number); require( newMaxQuorumVotesBPS <= MAX_QUORUM_VOTES_BPS_UPPER_BOUND, @@ -396,7 +372,7 @@ library NounsDAOV3Admin { uint16 oldMaxQuorumVotesBPS = params.maxQuorumVotesBPS; params.maxQuorumVotesBPS = newMaxQuorumVotesBPS; - _writeQuorumParamsCheckpoint(ds, params); + _writeQuorumParamsCheckpoint(params); emit MaxQuorumVotesBPSSet(oldMaxQuorumVotesBPS, newMaxQuorumVotesBPS); } @@ -405,16 +381,13 @@ library NounsDAOV3Admin { * @notice Admin function for setting the dynamic quorum coefficient * @param newQuorumCoefficient the new coefficient, as a fixed point integer with 6 decimals */ - function _setQuorumCoefficient(NounsDAOStorageV3.StorageV3 storage ds, uint32 newQuorumCoefficient) - external - onlyAdmin(ds) - { - NounsDAOStorageV3.DynamicQuorumParams memory params = ds.getDynamicQuorumParamsAt(block.number); + function _setQuorumCoefficient(uint32 newQuorumCoefficient) external onlyAdmin { + NounsDAOTypes.DynamicQuorumParams memory params = ds().getDynamicQuorumParamsAt(block.number); uint32 oldQuorumCoefficient = params.quorumCoefficient; params.quorumCoefficient = newQuorumCoefficient; - _writeQuorumParamsCheckpoint(ds, params); + _writeQuorumParamsCheckpoint(params); emit QuorumCoefficientSet(oldQuorumCoefficient, newQuorumCoefficient); } @@ -430,11 +403,10 @@ library NounsDAOV3Admin { * @param newQuorumCoefficient the new coefficient, as a fixed point integer with 6 decimals */ function _setDynamicQuorumParams( - NounsDAOStorageV3.StorageV3 storage ds, uint16 newMinQuorumVotesBPS, uint16 newMaxQuorumVotesBPS, uint32 newQuorumCoefficient - ) public onlyAdmin(ds) { + ) public onlyAdmin { if ( newMinQuorumVotesBPS < MIN_QUORUM_VOTES_BPS_LOWER_BOUND || newMinQuorumVotesBPS > MIN_QUORUM_VOTES_BPS_UPPER_BOUND @@ -448,14 +420,14 @@ library NounsDAOV3Admin { revert MinQuorumBPSGreaterThanMaxQuorumBPS(); } - NounsDAOStorageV3.DynamicQuorumParams memory oldParams = ds.getDynamicQuorumParamsAt(block.number); + NounsDAOTypes.DynamicQuorumParams memory oldParams = ds().getDynamicQuorumParamsAt(block.number); - NounsDAOStorageV3.DynamicQuorumParams memory params = NounsDAOStorageV3.DynamicQuorumParams({ + NounsDAOTypes.DynamicQuorumParams memory params = NounsDAOTypes.DynamicQuorumParams({ minQuorumVotesBPS: newMinQuorumVotesBPS, maxQuorumVotesBPS: newMaxQuorumVotesBPS, quorumCoefficient: newQuorumCoefficient }); - _writeQuorumParamsCheckpoint(ds, params); + _writeQuorumParamsCheckpoint(params); emit MinQuorumVotesBPSSet(oldParams.minQuorumVotesBPS, params.minQuorumVotesBPS); emit MaxQuorumVotesBPSSet(oldParams.maxQuorumVotesBPS, params.maxQuorumVotesBPS); @@ -465,7 +437,7 @@ library NounsDAOV3Admin { /** * @notice Withdraws all the ETH in the contract. This is callable only by the admin (timelock). */ - function _withdraw(NounsDAOStorageV3.StorageV3 storage ds) external onlyAdmin(ds) returns (uint256, bool) { + function _withdraw() external onlyAdmin returns (uint256, bool) { uint256 amount = address(this).balance; (bool sent, ) = msg.sender.call{ value: amount }(''); @@ -474,35 +446,12 @@ library NounsDAOV3Admin { return (amount, sent); } - /** - * @notice Admin function for setting the proposal id at which vote snapshots start using the voting start block - * instead of the proposal creation block. - * Sets it to the next proposal id. - */ - function _setVoteSnapshotBlockSwitchProposalId(NounsDAOStorageV3.StorageV3 storage ds) external onlyAdmin(ds) { - uint256 oldVoteSnapshotBlockSwitchProposalId = ds.voteSnapshotBlockSwitchProposalId; - if (oldVoteSnapshotBlockSwitchProposalId > 0) { - revert VoteSnapshotSwitchAlreadySet(); - } - - uint256 newVoteSnapshotBlockSwitchProposalId = ds.proposalCount + 1; - ds.voteSnapshotBlockSwitchProposalId = newVoteSnapshotBlockSwitchProposalId; - - emit VoteSnapshotBlockSwitchProposalIdSet( - oldVoteSnapshotBlockSwitchProposalId, - newVoteSnapshotBlockSwitchProposalId - ); - } - /** * @notice Admin function for setting the fork DAO deployer contract */ - function _setForkDAODeployer(NounsDAOStorageV3.StorageV3 storage ds, address newForkDAODeployer) - external - onlyAdmin(ds) - { - address oldForkDAODeployer = address(ds.forkDAODeployer); - ds.forkDAODeployer = IForkDAODeployer(newForkDAODeployer); + function _setForkDAODeployer(address newForkDAODeployer) public onlyAdmin { + address oldForkDAODeployer = address(ds().forkDAODeployer); + ds().forkDAODeployer = IForkDAODeployer(newForkDAODeployer); emit ForkDAODeployerSet(oldForkDAODeployer, newForkDAODeployer); } @@ -510,27 +459,24 @@ library NounsDAOV3Admin { /** * @notice Admin function for setting the ERC20 tokens that are used when splitting funds to a fork */ - function _setErc20TokensToIncludeInFork(NounsDAOStorageV3.StorageV3 storage ds, address[] calldata erc20tokens) - external - onlyAdmin(ds) - { + function _setErc20TokensToIncludeInFork(address[] calldata erc20tokens) public onlyAdmin { checkForDuplicates(erc20tokens); - emit ERC20TokensToIncludeInForkSet(ds.erc20TokensToIncludeInFork, erc20tokens); + emit ERC20TokensToIncludeInForkSet(ds().erc20TokensToIncludeInFork, erc20tokens); - ds.erc20TokensToIncludeInFork = erc20tokens; + ds().erc20TokensToIncludeInFork = erc20tokens; } /** * @notice Admin function for setting the fork escrow contract */ - function _setForkEscrow(NounsDAOStorageV3.StorageV3 storage ds, address newForkEscrow) external onlyAdmin(ds) { - emit ForkEscrowSet(address(ds.forkEscrow), newForkEscrow); + function _setForkEscrow(address newForkEscrow) public onlyAdmin { + emit ForkEscrowSet(address(ds().forkEscrow), newForkEscrow); - ds.forkEscrow = INounsDAOForkEscrow(newForkEscrow); + ds().forkEscrow = INounsDAOForkEscrow(newForkEscrow); } - function _setForkPeriod(NounsDAOStorageV3.StorageV3 storage ds, uint256 newForkPeriod) external onlyAdmin(ds) { + function _setForkPeriod(uint256 newForkPeriod) public onlyAdmin { if (newForkPeriod > MAX_FORK_PERIOD) { revert ForkPeriodTooLong(); } @@ -539,22 +485,41 @@ library NounsDAOV3Admin { revert ForkPeriodTooShort(); } - emit ForkPeriodSet(ds.forkPeriod, newForkPeriod); + emit ForkPeriodSet(ds().forkPeriod, newForkPeriod); - ds.forkPeriod = newForkPeriod; + ds().forkPeriod = newForkPeriod; } /** * @notice Admin function for setting the fork threshold * @param newForkThresholdBPS the new fork proposal threshold, in basis points */ - function _setForkThresholdBPS(NounsDAOStorageV3.StorageV3 storage ds, uint256 newForkThresholdBPS) - external - onlyAdmin(ds) - { - emit ForkThresholdSet(ds.forkThresholdBPS, newForkThresholdBPS); + function _setForkThresholdBPS(uint256 newForkThresholdBPS) public onlyAdmin { + emit ForkThresholdSet(ds().forkThresholdBPS, newForkThresholdBPS); - ds.forkThresholdBPS = newForkThresholdBPS; + ds().forkThresholdBPS = newForkThresholdBPS; + } + + /** + * @notice Admin function for setting the fork related parameters + * @param forkEscrow_ the fork escrow contract + * @param forkDAODeployer_ the fork dao deployer contract + * @param erc20TokensToIncludeInFork_ the ERC20 tokens used when splitting funds to a fork + * @param forkPeriod_ the period during which it's possible to join a fork after exeuction + * @param forkThresholdBPS_ the threshold required of escrowed nouns in order to execute a fork + */ + function _setForkParams( + address forkEscrow_, + address forkDAODeployer_, + address[] calldata erc20TokensToIncludeInFork_, + uint256 forkPeriod_, + uint256 forkThresholdBPS_ + ) external { + _setForkEscrow(forkEscrow_); + _setForkDAODeployer(forkDAODeployer_); + _setErc20TokensToIncludeInFork(erc20TokensToIncludeInFork_); + _setForkPeriod(forkPeriod_); + _setForkThresholdBPS(forkThresholdBPS_); } /** @@ -563,30 +528,31 @@ library NounsDAOV3Admin { * @param timelockV1 the new timelockV1 contract * @param admin the new admin address */ - function _setTimelocksAndAdmin( - NounsDAOStorageV3.StorageV3 storage ds, - address timelock, - address timelockV1, - address admin - ) external onlyAdmin(ds) { - ds.timelock = INounsDAOExecutorV2(timelock); - ds.timelockV1 = INounsDAOExecutor(timelockV1); - ds.admin = admin; + function _setTimelocksAndAdmin(address timelock, address timelockV1, address admin) external onlyAdmin { + ds().timelock = INounsDAOExecutorV2(timelock); + ds().timelockV1 = INounsDAOExecutor(timelockV1); + ds().admin = admin; emit TimelocksAndAdminSet(timelock, timelockV1, admin); } - function _writeQuorumParamsCheckpoint( - NounsDAOStorageV3.StorageV3 storage ds, - NounsDAOStorageV3.DynamicQuorumParams memory params - ) internal { + /** + * @notice Admin function for zeroing out the state variable `voteSnapshotBlockSwitchProposalId` + * @dev We want to zero-out this state slot so we can remove this temporary variable from contract code and + * be ready to reuse this slot. + */ + function _zeroOutVoteSnapshotBlockSwitchProposalId() external onlyAdmin { + ds().voteSnapshotBlockSwitchProposalId = 0; + } + + function _writeQuorumParamsCheckpoint(NounsDAOTypes.DynamicQuorumParams memory params) internal { uint32 blockNumber = safe32(block.number, 'block number exceeds 32 bits'); - uint256 pos = ds.quorumParamsCheckpoints.length; - if (pos > 0 && ds.quorumParamsCheckpoints[pos - 1].fromBlock == blockNumber) { - ds.quorumParamsCheckpoints[pos - 1].params = params; + uint256 pos = ds().quorumParamsCheckpoints.length; + if (pos > 0 && ds().quorumParamsCheckpoints[pos - 1].fromBlock == blockNumber) { + ds().quorumParamsCheckpoints[pos - 1].params = params; } else { - ds.quorumParamsCheckpoints.push( - NounsDAOStorageV3.DynamicQuorumParamsCheckpoint({ fromBlock: blockNumber, params: params }) + ds().quorumParamsCheckpoints.push( + NounsDAOTypes.DynamicQuorumParamsCheckpoint({ fromBlock: blockNumber, params: params }) ); } } @@ -605,4 +571,16 @@ library NounsDAOV3Admin { } } } + + /*** + * @dev Used to access the DAO's storage struct without receiving it as a function argument. + * Created as part of the DAO logic refactor where this admin library is called in the DAO's fallback function, + * since the DAO no longer makes explicit calls to this library. + * This function assumes the storage struct starts at slot 0. + */ + function ds() internal pure returns (NounsDAOTypes.Storage storage ds_) { + assembly { + ds_.slot := 0 + } + } } diff --git a/packages/nouns-contracts/contracts/governance/NounsDAOV3DynamicQuorum.sol b/packages/nouns-contracts/contracts/governance/NounsDAODynamicQuorum.sol similarity index 81% rename from packages/nouns-contracts/contracts/governance/NounsDAOV3DynamicQuorum.sol rename to packages/nouns-contracts/contracts/governance/NounsDAODynamicQuorum.sol index 7c83928b9a..371ea1c4f2 100644 --- a/packages/nouns-contracts/contracts/governance/NounsDAOV3DynamicQuorum.sol +++ b/packages/nouns-contracts/contracts/governance/NounsDAODynamicQuorum.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-3.0 -/// @title Library for NounsDAOLogicV3 contract containing functions related to quorum calculations +/// @title Library for Nouns DAO Logic containing functions related to quorum calculations /********************************* * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ * @@ -18,10 +18,10 @@ pragma solidity ^0.8.19; import './NounsDAOInterfaces.sol'; -import { NounsDAOV3Fork } from './fork/NounsDAOV3Fork.sol'; +import { NounsDAOFork } from './fork/NounsDAOFork.sol'; -library NounsDAOV3DynamicQuorum { - using NounsDAOV3Fork for NounsDAOStorageV3.StorageV3; +library NounsDAODynamicQuorum { + using NounsDAOFork for NounsDAOTypes.Storage; error UnsafeUint16Cast(); @@ -29,8 +29,8 @@ library NounsDAOV3DynamicQuorum { * @notice Quorum votes required for a specific proposal to succeed * Differs from `GovernerBravo` which uses fixed amount */ - function quorumVotes(NounsDAOStorageV3.StorageV3 storage ds, uint256 proposalId) internal view returns (uint256) { - NounsDAOStorageV3.Proposal storage proposal = ds._proposals[proposalId]; + function quorumVotes(NounsDAOTypes.Storage storage ds, uint256 proposalId) internal view returns (uint256) { + NounsDAOTypes.Proposal storage proposal = ds._proposals[proposalId]; if (proposal.totalSupply == 0) { return proposal.quorumVotes; } @@ -58,7 +58,7 @@ library NounsDAOV3DynamicQuorum { function dynamicQuorumVotes( uint256 againstVotes, uint256 totalSupply, - NounsDAOStorageV3.DynamicQuorumParams memory params + NounsDAOTypes.DynamicQuorumParams memory params ) public pure returns (uint256) { uint256 againstVotesBPS = (10000 * againstVotes) / totalSupply; uint256 quorumAdjustmentBPS = (params.quorumCoefficient * againstVotesBPS) / 1e6; @@ -74,17 +74,16 @@ library NounsDAOV3DynamicQuorum { * @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(NounsDAOStorageV3.StorageV3 storage ds, uint256 blockNumber_) - internal - view - returns (NounsDAOStorageV3.DynamicQuorumParams memory) - { + function getDynamicQuorumParamsAt( + NounsDAOTypes.Storage storage ds, + uint256 blockNumber_ + ) internal view returns (NounsDAOTypes.DynamicQuorumParams memory) { uint32 blockNumber = safe32(blockNumber_, 'NounsDAO::getDynamicQuorumParamsAt: block number exceeds 32 bits'); uint256 len = ds.quorumParamsCheckpoints.length; if (len == 0) { return - NounsDAOStorageV3.DynamicQuorumParams({ + NounsDAOTypes.DynamicQuorumParams({ minQuorumVotesBPS: safe16(ds.quorumVotesBPS), maxQuorumVotesBPS: safe16(ds.quorumVotesBPS), quorumCoefficient: 0 @@ -97,7 +96,7 @@ library NounsDAOV3DynamicQuorum { if (ds.quorumParamsCheckpoints[0].fromBlock > blockNumber) { return - NounsDAOStorageV3.DynamicQuorumParams({ + NounsDAOTypes.DynamicQuorumParams({ minQuorumVotesBPS: safe16(ds.quorumVotesBPS), maxQuorumVotesBPS: safe16(ds.quorumVotesBPS), quorumCoefficient: 0 @@ -108,7 +107,7 @@ library NounsDAOV3DynamicQuorum { uint256 upper = len - 1; while (upper > lower) { uint256 center = upper - (upper - lower) / 2; - NounsDAOStorageV3.DynamicQuorumParamsCheckpoint memory cp = ds.quorumParamsCheckpoints[center]; + NounsDAOTypes.DynamicQuorumParamsCheckpoint memory cp = ds.quorumParamsCheckpoints[center]; if (cp.fromBlock == blockNumber) { return cp.params; } else if (cp.fromBlock < blockNumber) { @@ -123,22 +122,20 @@ library NounsDAOV3DynamicQuorum { /** * @notice Current min quorum votes using Nouns adjusted total supply */ - function minQuorumVotes(NounsDAOStorageV3.StorageV3 storage ds, uint256 adjustedTotalSupply) - internal - view - returns (uint256) - { + function minQuorumVotes( + NounsDAOTypes.Storage storage ds, + uint256 adjustedTotalSupply + ) internal view returns (uint256) { return bps2Uint(getDynamicQuorumParamsAt(ds, block.number).minQuorumVotesBPS, adjustedTotalSupply); } /** * @notice Current max quorum votes using Nouns adjusted total supply */ - function maxQuorumVotes(NounsDAOStorageV3.StorageV3 storage ds, uint256 adjustedTotalSupply) - internal - view - returns (uint256) - { + function maxQuorumVotes( + NounsDAOTypes.Storage storage ds, + uint256 adjustedTotalSupply + ) internal view returns (uint256) { return bps2Uint(getDynamicQuorumParamsAt(ds, block.number).maxQuorumVotesBPS, adjustedTotalSupply); } diff --git a/packages/nouns-contracts/contracts/governance/NounsDAOInterfaces.sol b/packages/nouns-contracts/contracts/governance/NounsDAOInterfaces.sol index 8fb0b4d3d4..591b66e3a1 100644 --- a/packages/nouns-contracts/contracts/governance/NounsDAOInterfaces.sol +++ b/packages/nouns-contracts/contracts/governance/NounsDAOInterfaces.sol @@ -32,9 +32,9 @@ // NounsDAOStorageV3 // See NounsDAOLogicV3.sol for more details. -pragma solidity ^0.8.6; +pragma solidity ^0.8.19; -contract NounsDAOEvents { +interface NounsDAOEventsV3 { /// @notice An event emitted when a new proposal is created event ProposalCreated( uint256 id, @@ -89,9 +89,6 @@ contract NounsDAOEvents { /// @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); @@ -106,9 +103,7 @@ contract NounsDAOEvents { /// @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); @@ -126,25 +121,17 @@ contract NounsDAOEventsV2 is NounsDAOEvents { /// @notice Emitted when pendingVetoer is changed event NewPendingVetoer(address oldPendingVetoer, address newPendingVetoer); -} -contract NounsDAOEventsV3 is NounsDAOEventsV2 { /// @notice An event emitted when a new proposal is created, which includes additional information /// @dev V3 adds `signers`, `updatePeriodEndBlock` compared to the V1/V2 event. + /// @dev V4: Removed data that's already emitted in `ProposalCreated`, added clientId event ProposalCreatedWithRequirements( uint256 id, - address proposer, address[] signers, - address[] targets, - uint256[] values, - string[] signatures, - bytes[] calldatas, - uint256 startBlock, - uint256 endBlock, uint256 updatePeriodEndBlock, uint256 proposalThreshold, uint256 quorumVotes, - string description + uint32 indexed clientId ); /// @notice Emitted when a proposal is created to be executed on timelockV1 @@ -202,12 +189,6 @@ contract NounsDAOEventsV3 is NounsDAOEventsV2 { uint32 newProposalUpdatablePeriodInBlocks ); - /// @notice Emitted when the proposal id at which vote snapshot block changes is set - event VoteSnapshotBlockSwitchProposalIdSet( - uint256 oldVoteSnapshotBlockSwitchProposalId, - uint256 newVoteSnapshotBlockSwitchProposalId - ); - /// @notice Emitted when the erc20 tokens to include in a fork are set event ERC20TokensToIncludeInForkSet(address[] oldErc20Tokens, address[] newErc20tokens); @@ -258,285 +239,11 @@ contract NounsDAOEventsV3 is NounsDAOEventsV2 { /// @notice Emitted when withdrawing nouns from escrow increases adjusted total supply event DAONounsSupplyIncreasedFromEscrow(uint256 numTokens, address to); -} - -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; - } + /// @notice An event emitted when a vote has been cast with a non-zero client Id. + /// @dev Assumes the `VoteCast` event is emitted, and that indexers can use the voter address and propose ID to + /// find the relevant vote and set its client ID. + event VoteCastWithClientId(address indexed voter, uint256 indexed proposalId, uint32 indexed clientId); } interface INounsDAOExecutor { @@ -578,17 +285,9 @@ interface NounsTokenLike { function totalSupply() external view returns (uint256); - function transferFrom( - address from, - address to, - uint256 tokenId - ) external; + function transferFrom(address from, address to, uint256 tokenId) external; - function safeTransferFrom( - address from, - address to, - uint256 tokenId - ) external; + function safeTransferFrom(address from, address to, uint256 tokenId) external; function balanceOf(address owner) external view returns (uint256 balance); @@ -602,9 +301,10 @@ interface NounsTokenLike { } interface IForkDAODeployer { - function deployForkDAO(uint256 forkingPeriodEndTimestamp, INounsDAOForkEscrow forkEscrowAddress) - external - returns (address treasury, address token); + function deployForkDAO( + uint256 forkingPeriodEndTimestamp, + INounsDAOForkEscrow forkEscrowAddress + ) external returns (address treasury, address token); function tokenImpl() external view returns (address); @@ -618,11 +318,7 @@ interface IForkDAODeployer { interface INounsDAOExecutorV2 is INounsDAOExecutor { function sendETH(address recipient, uint256 ethToSend) external; - function sendERC20( - address recipient, - address erc20Token, - uint256 tokensToSend - ) external; + function sendERC20(address recipient, address erc20Token, uint256 tokensToSend) external; } interface INounsDAOForkEscrow { @@ -647,10 +343,8 @@ interface INounsDAOForkEscrow { function ownerOfEscrowedToken(uint32 forkId_, uint256 tokenId) external view returns (address); } -contract NounsDAOStorageV3 { - StorageV3 ds; - - struct StorageV3 { +interface NounsDAOTypes { + struct Storage { // ================ PROXY ================ // /// @notice Administrator for this contract address admin; @@ -710,15 +404,18 @@ contract NounsDAOStorageV3 { uint256 forkThresholdBPS; /// @notice Address of the original timelock INounsDAOExecutor timelockV1; - /// @notice The proposal at which to start using `startBlock` instead of `creationBlock` for vote snapshots /// @dev Make sure this stays the last variable in this struct, so we can delete it in the next version - /// @dev To be zeroed-out and removed in a V3.1 fix version once the switch takes place + /// @dev To be zeroed-out in the upcoming DAO upgrade. uint256 voteSnapshotBlockSwitchProposalId; } struct Proposal { /// @notice Unique id for looking up a proposal - uint256 id; + uint32 id; + /// @notice client id for rewards + uint32 clientId; + /// @notice currently unused + uint192 _gap; /// @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 @@ -756,7 +453,9 @@ contract NounsDAOStorageV3 { /// @notice The total supply at the time of proposal creation uint256 totalSupply; /// @notice The block at which this proposal was created - uint64 creationBlock; + uint32 creationBlock; + /// @notice The timestamp of the block at which this proposal was created + uint32 creationTimestamp; /// @notice The last block which allows updating a proposal's description and transactions uint64 updatePeriodEndBlock; /// @notice Starts at 0 and is set to the block at which the objection period ends when the objection period is initiated @@ -767,6 +466,15 @@ contract NounsDAOStorageV3 { address[] signers; /// @notice When true, a proposal would be executed on timelockV1 instead of the current timelock bool executeOnTimelockV1; + /// @notice How many votes and vote transactions each clientId contributed to this proposal + mapping(uint32 => ClientVoteData) voteClients; + } + + struct ClientVoteData { + /// @notice The number of votes the client facilitated on a proposal + uint32 votes; + /// @notice The number of vote transactions the client facilitated on a proposal + uint32 txs; } /// @notice Ballot receipt record for a voter @@ -788,7 +496,28 @@ contract NounsDAOStorageV3 { uint256 expirationTimestamp; } - struct ProposalCondensed { + /// @notice A subset of Proposal data, used for client rewards calculation + struct ProposalForRewards { + /// @notice The proposal's voting period end block + uint256 endBlock; + /// @notice The proposal's objection period end block + uint256 objectionPeriodEndBlock; + /// @notice The proposal's For votes count + uint256 forVotes; + /// @notice The proposal's Against votes count + uint256 againstVotes; + /// @notice The proposal's Abstain votes count + uint256 abstainVotes; + /// @notice The proposal's snapshot of total supply + uint256 totalSupply; + /// @notice The timestamp of the block at which the proposal was created + uint256 creationTimestamp; + /// @notice The ID for the client that facilitated the proposal + uint32 clientId; + ClientVoteData[] voteData; + } + + struct ProposalCondensedV3 { /// @notice Unique id for looking up a proposal uint256 id; /// @notice Creator of the proposal @@ -829,6 +558,39 @@ contract NounsDAOStorageV3 { bool executeOnTimelockV1; } + struct ProposalCondensedV2 { + /// @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; + } + 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; @@ -871,3 +633,7 @@ contract NounsDAOStorageV3 { Updatable } } + +contract NounsDAOStorage is NounsDAOTypes { + Storage ds; +} diff --git a/packages/nouns-contracts/contracts/governance/NounsDAOLogicV1.sol b/packages/nouns-contracts/contracts/governance/NounsDAOLogicV1.sol deleted file mode 100644 index 5654382d05..0000000000 --- a/packages/nouns-contracts/contracts/governance/NounsDAOLogicV1.sol +++ /dev/null @@ -1,683 +0,0 @@ -// SPDX-License-Identifier: BSD-3-Clause - -/// @title The Nouns DAO logic version 1 - -/********************************* - * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ * - * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ * - * ░░░░░░█████████░░█████████░░░ * - * ░░░░░░██░░░████░░██░░░████░░░ * - * ░░██████░░░████████░░░████░░░ * - * ░░██░░██░░░████░░██░░░████░░░ * - * ░░██░░██░░░████░░██░░░████░░░ * - * ░░░░░░█████████░░█████████░░░ * - * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ * - * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ * - *********************************/ - -// LICENSE -// NounsDAOLogicV1.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 -// NounsDAOLogicV1 adds: -// - Proposal Threshold basis points instead of fixed number -// due to the Noun token's increasing supply -// -// - Quorum Votes basis points instead of fixed number -// due to the Noun token's increasing supply -// -// - Per proposal storing of fixed `proposalThreshold` -// and `quorumVotes` calculated using the Noun token's total supply -// at the block the proposal was created and the basis point parameters -// -// - `ProposalCreatedWithRequirements` event that emits `ProposalCreated` parameters with -// the addition of `proposalThreshold` and `quorumVotes` -// -// - Votes are counted from the block a proposal is created instead of -// the proposal's voting start block to align with the parameters -// stored with the proposal -// -// - Veto ability which allows `veteor` to halt any proposal at any stage unless -// the proposal is executed. -// The `veto(uint proposalId)` logic is a modified version of `cancel(uint proposalId)` -// A `vetoed` flag was added to the `Proposal` struct to support this. -// -// NounsDAOLogicV1 removes: -// - `initialProposalId` and `_initiate()` due to this being the -// first instance of the governance contract unlike -// GovernorBravo which upgrades GovernorAlpha -// -// - Value passed along using `timelock.executeTransaction{value: proposal.value}` -// in `execute(uint proposalId)`. This contract should not hold funds and does not -// implement `receive()` or `fallback()` functions. -// - -pragma solidity ^0.8.6; - -import './NounsDAOInterfaces.sol'; - -contract NounsDAOLogicV1 is NounsDAOStorageV1, NounsDAOEvents { - /// @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 minimum setable quorum votes basis points - uint256 public constant MIN_QUORUM_VOTES_BPS = 200; // 200 basis points or 2% - - /// @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 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)'); - - /** - * @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 quorumVotesBPS_ The initial quorum votes threshold in basis points - */ - function initialize( - address timelock_, - address nouns_, - address vetoer_, - uint256 votingPeriod_, - uint256 votingDelay_, - uint256 proposalThresholdBPS_, - uint256 quorumVotesBPS_ - ) public virtual { - require(address(timelock) == address(0), 'NounsDAO::initialize: can only initialize once'); - require(msg.sender == admin, 'NounsDAO::initialize: admin only'); - 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' - ); - require( - quorumVotesBPS_ >= MIN_QUORUM_VOTES_BPS && quorumVotesBPS_ <= MAX_QUORUM_VOTES_BPS, - 'NounsDAO::initialize: invalid proposal threshold' - ); - - emit VotingPeriodSet(votingPeriod, votingPeriod_); - emit VotingDelaySet(votingDelay, votingDelay_); - emit ProposalThresholdBPSSet(proposalThresholdBPS, proposalThresholdBPS_); - emit QuorumVotesBPSSet(quorumVotesBPS, quorumVotesBPS_); - - timelock = INounsDAOExecutor(timelock_); - nouns = NounsTokenLike(nouns_); - vetoer = vetoer_; - votingPeriod = votingPeriod_; - votingDelay = votingDelay_; - proposalThresholdBPS = proposalThresholdBPS_; - quorumVotesBPS = quorumVotesBPS_; - } - - 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.quorumVotes = bps2Uint(quorumVotesBPS, temp.totalSupply); - 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; - - 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 `quorumVotes` - emit ProposalCreatedWithRequirements( - newProposal.id, - msg.sender, - targets, - values, - signatures, - calldatas, - newProposal.startBlock, - newProposal.endBlock, - newProposal.proposalThreshold, - newProposal.quorumVotes, - 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 { - require(state(proposalId) != ProposalState.Executed, 'NounsDAO::cancel: cannot cancel executed proposal'); - - 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 { - require(vetoer != address(0), 'NounsDAO::veto: veto power burned'); - require(msg.sender == vetoer, 'NounsDAO::veto: only vetoer'); - require(state(proposalId) != ProposalState.Executed, 'NounsDAO::veto: cannot veto executed proposal'); - - 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 < proposal.quorumVotes) { - 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 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 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, proposal.startBlock - votingDelay); - - 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 { - require(msg.sender == admin, 'NounsDAO::_setVotingDelay: admin only'); - 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 { - require(msg.sender == admin, 'NounsDAO::_setVotingPeriod: admin only'); - 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 { - require(msg.sender == admin, 'NounsDAO::_setProposalThresholdBPS: admin only'); - require( - newProposalThresholdBPS >= MIN_PROPOSAL_THRESHOLD_BPS && - newProposalThresholdBPS <= MAX_PROPOSAL_THRESHOLD_BPS, - 'NounsDAO::_setProposalThreshold: invalid proposal threshold' - ); - uint256 oldProposalThresholdBPS = proposalThresholdBPS; - proposalThresholdBPS = newProposalThresholdBPS; - - emit ProposalThresholdBPSSet(oldProposalThresholdBPS, proposalThresholdBPS); - } - - /** - * @notice Admin function for setting the quorum votes basis points - * @dev newQuorumVotesBPS must be greater than the hardcoded min - * @param newQuorumVotesBPS new proposal threshold - */ - function _setQuorumVotesBPS(uint256 newQuorumVotesBPS) external { - require(msg.sender == admin, 'NounsDAO::_setQuorumVotesBPS: admin only'); - require( - newQuorumVotesBPS >= MIN_QUORUM_VOTES_BPS && newQuorumVotesBPS <= MAX_QUORUM_VOTES_BPS, - 'NounsDAO::_setProposalThreshold: invalid proposal threshold' - ); - uint256 oldQuorumVotesBPS = quorumVotesBPS; - quorumVotesBPS = newQuorumVotesBPS; - - emit QuorumVotesBPSSet(oldQuorumVotesBPS, quorumVotesBPS); - } - - /** - * @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 Changes vetoer address - * @dev Vetoer function for updating vetoer address - */ - function _setVetoer(address newVetoer) public { - require(msg.sender == vetoer, 'NounsDAO::_setVetoer: vetoer only'); - - emit NewVetoer(vetoer, newVetoer); - - vetoer = newVetoer; - } - - /** - * @notice Burns veto priviledges - * @dev Vetoer function destroying veto power forever - */ - function _burnVetoPower() public { - // Check caller is pendingAdmin and pendingAdmin ≠ address(0) - require(msg.sender == vetoer, 'NounsDAO::_burnVetoPower: vetoer only'); - - _setVetoer(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()); - } - - /** - * @notice Current quorum votes using Noun Total Supply - * Differs from `GovernerBravo` which uses fixed amount - */ - function quorumVotes() public view returns (uint256) { - return bps2Uint(quorumVotesBPS, 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; - } -} diff --git a/packages/nouns-contracts/contracts/governance/NounsDAOLogicV2.sol b/packages/nouns-contracts/contracts/governance/NounsDAOLogicV2.sol deleted file mode 100644 index ff426a8108..0000000000 --- a/packages/nouns-contracts/contracts/governance/NounsDAOLogicV2.sol +++ /dev/null @@ -1,1091 +0,0 @@ -// 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 {} -} diff --git a/packages/nouns-contracts/contracts/governance/NounsDAOLogicV3.sol b/packages/nouns-contracts/contracts/governance/NounsDAOLogicV4.sol similarity index 71% rename from packages/nouns-contracts/contracts/governance/NounsDAOLogicV3.sol rename to packages/nouns-contracts/contracts/governance/NounsDAOLogicV4.sol index 00c5ccdc3b..f3a6a002e4 100644 --- a/packages/nouns-contracts/contracts/governance/NounsDAOLogicV3.sol +++ b/packages/nouns-contracts/contracts/governance/NounsDAOLogicV4.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: BSD-3-Clause -/// @title The Nouns DAO logic version 3 +/// @title The Nouns DAO logic version 4 /********************************* * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ * @@ -56,18 +56,19 @@ pragma solidity ^0.8.19; import './NounsDAOInterfaces.sol'; -import { NounsDAOV3Admin } from './NounsDAOV3Admin.sol'; -import { NounsDAOV3DynamicQuorum } from './NounsDAOV3DynamicQuorum.sol'; -import { NounsDAOV3Votes } from './NounsDAOV3Votes.sol'; -import { NounsDAOV3Proposals } from './NounsDAOV3Proposals.sol'; -import { NounsDAOV3Fork } from './fork/NounsDAOV3Fork.sol'; - -contract NounsDAOLogicV3 is NounsDAOStorageV3, NounsDAOEventsV3 { - using NounsDAOV3Admin for StorageV3; - using NounsDAOV3DynamicQuorum for StorageV3; - using NounsDAOV3Votes for StorageV3; - using NounsDAOV3Proposals for StorageV3; - using NounsDAOV3Fork for StorageV3; +import { NounsDAOAdmin } from './NounsDAOAdmin.sol'; +import { NounsDAODynamicQuorum } from './NounsDAODynamicQuorum.sol'; +import { NounsDAOVotes } from './NounsDAOVotes.sol'; +import { NounsDAOProposals } from './NounsDAOProposals.sol'; +import { NounsDAOFork } from './fork/NounsDAOFork.sol'; +import { Address } from '@openzeppelin/contracts/utils/Address.sol'; + +contract NounsDAOLogicV4 is NounsDAOStorage, NounsDAOEventsV3 { + using NounsDAOAdmin for Storage; + using NounsDAODynamicQuorum for Storage; + using NounsDAOVotes for Storage; + using NounsDAOProposals for Storage; + using NounsDAOFork for Storage; /** * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ @@ -77,37 +78,37 @@ contract NounsDAOLogicV3 is NounsDAOStorageV3, NounsDAOEventsV3 { /// @notice The minimum setable proposal threshold function MIN_PROPOSAL_THRESHOLD_BPS() public pure returns (uint256) { - return NounsDAOV3Admin.MIN_PROPOSAL_THRESHOLD_BPS; + return NounsDAOAdmin.MIN_PROPOSAL_THRESHOLD_BPS; } /// @notice The maximum setable proposal threshold function MAX_PROPOSAL_THRESHOLD_BPS() public pure returns (uint256) { - return NounsDAOV3Admin.MAX_PROPOSAL_THRESHOLD_BPS; + return NounsDAOAdmin.MAX_PROPOSAL_THRESHOLD_BPS; } /// @notice The minimum setable voting period in blocks function MIN_VOTING_PERIOD() public pure returns (uint256) { - return NounsDAOV3Admin.MIN_VOTING_PERIOD_BLOCKS; + return NounsDAOAdmin.MIN_VOTING_PERIOD_BLOCKS; } /// @notice The max setable voting period in blocks function MAX_VOTING_PERIOD() public pure returns (uint256) { - return NounsDAOV3Admin.MAX_VOTING_PERIOD_BLOCKS; + return NounsDAOAdmin.MAX_VOTING_PERIOD_BLOCKS; } /// @notice The min setable voting delay in blocks function MIN_VOTING_DELAY() public pure returns (uint256) { - return NounsDAOV3Admin.MIN_VOTING_DELAY_BLOCKS; + return NounsDAOAdmin.MIN_VOTING_DELAY_BLOCKS; } /// @notice The max setable voting delay in blocks function MAX_VOTING_DELAY() public pure returns (uint256) { - return NounsDAOV3Admin.MAX_VOTING_DELAY_BLOCKS; + return NounsDAOAdmin.MAX_VOTING_DELAY_BLOCKS; } /// @notice The maximum number of actions that can be included in a proposal function proposalMaxOperations() public pure returns (uint256) { - return NounsDAOV3Proposals.PROPOSAL_MAX_OPERATIONS; + return NounsDAOProposals.PROPOSAL_MAX_OPERATIONS; } /** @@ -152,23 +153,23 @@ contract NounsDAOLogicV3 is NounsDAOStorageV3, NounsDAOEventsV3 { if (timelock_ == address(0)) revert InvalidTimelockAddress(); if (nouns_ == address(0)) revert InvalidNounsAddress(); - ds._setVotingPeriod(daoParams_.votingPeriod); - ds._setVotingDelay(daoParams_.votingDelay); - ds._setProposalThresholdBPS(daoParams_.proposalThresholdBPS); + NounsDAOAdmin._setVotingPeriod(daoParams_.votingPeriod); + NounsDAOAdmin._setVotingDelay(daoParams_.votingDelay); + NounsDAOAdmin._setProposalThresholdBPS(daoParams_.proposalThresholdBPS); ds.timelock = INounsDAOExecutorV2(timelock_); ds.nouns = NounsTokenLike(nouns_); ds.forkEscrow = INounsDAOForkEscrow(forkEscrow_); ds.forkDAODeployer = IForkDAODeployer(forkDAODeployer_); ds.vetoer = vetoer_; - _setDynamicQuorumParams( + NounsDAOAdmin._setDynamicQuorumParams( dynamicQuorumParams_.minQuorumVotesBPS, dynamicQuorumParams_.maxQuorumVotesBPS, dynamicQuorumParams_.quorumCoefficient ); - ds._setLastMinuteWindowInBlocks(daoParams_.lastMinuteWindowInBlocks); - ds._setObjectionPeriodDurationInBlocks(daoParams_.objectionPeriodDurationInBlocks); - ds._setProposalUpdatablePeriodInBlocks(daoParams_.proposalUpdatablePeriodInBlocks); + NounsDAOAdmin._setLastMinuteWindowInBlocks(daoParams_.lastMinuteWindowInBlocks); + NounsDAOAdmin._setObjectionPeriodDurationInBlocks(daoParams_.objectionPeriodDurationInBlocks); + NounsDAOAdmin._setProposalUpdatablePeriodInBlocks(daoParams_.proposalUpdatablePeriodInBlocks); } /** @@ -192,8 +193,29 @@ contract NounsDAOLogicV3 is NounsDAOStorageV3, NounsDAOEventsV3 { string[] memory signatures, bytes[] memory calldatas, string memory description + ) external returns (uint256) { + return propose(targets, values, signatures, calldatas, description, 0); + } + + /** + * @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 + * @param clientId The ID of the client that faciliated posting the proposal onchain + * @return uint256 Proposal id of new proposal + */ + function propose( + address[] memory targets, + uint256[] memory values, + string[] memory signatures, + bytes[] memory calldatas, + string memory description, + uint32 clientId ) public returns (uint256) { - return ds.propose(NounsDAOV3Proposals.ProposalTxs(targets, values, signatures, calldatas), description); + return ds.propose(NounsDAOProposals.ProposalTxs(targets, values, signatures, calldatas), description, clientId); } /** @@ -216,8 +238,37 @@ contract NounsDAOLogicV3 is NounsDAOStorageV3, NounsDAOEventsV3 { ) public returns (uint256) { return ds.proposeOnTimelockV1( - NounsDAOV3Proposals.ProposalTxs(targets, values, signatures, calldatas), - description + NounsDAOProposals.ProposalTxs(targets, values, signatures, calldatas), + description, + 0 + ); + } + + /** + * @notice Function used to propose a new proposal. Sender must have delegates above the proposal threshold. + * This proposal would be executed via the timelockV1 contract. This is meant to be used in case timelockV1 + * is still holding funds or has special permissions to execute on certain contracts. + * @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 + * @param clientId The ID of the client that faciliated posting the proposal onchain + * @return uint256 Proposal id of new proposal + */ + function proposeOnTimelockV1( + address[] memory targets, + uint256[] memory values, + string[] memory signatures, + bytes[] memory calldatas, + string memory description, + uint32 clientId + ) public returns (uint256) { + return + ds.proposeOnTimelockV1( + NounsDAOProposals.ProposalTxs(targets, values, signatures, calldatas), + description, + clientId ); } @@ -225,7 +276,7 @@ contract NounsDAOLogicV3 is NounsDAOStorageV3, NounsDAOEventsV3 { * @notice Function used to propose a new proposal. Sender and signers must have delegates above the proposal threshold * Signers are regarded as co-proposers, and therefore have the ability to cancel the proposal at any time. * @param proposerSignatures Array of signers who have signed the proposal and their signatures. - * @dev The signatures follow EIP-712. See `PROPOSAL_TYPEHASH` in NounsDAOV3Proposals.sol + * @dev The signatures follow EIP-712. See `PROPOSAL_TYPEHASH` in NounsDAOProposals.sol * @param targets Target addresses for proposal calls * @param values Eth values for proposal calls * @param signatures Function signatures for proposal calls @@ -241,11 +292,37 @@ contract NounsDAOLogicV3 is NounsDAOStorageV3, NounsDAOEventsV3 { bytes[] memory calldatas, string memory description ) external returns (uint256) { + return proposeBySigs(proposerSignatures, targets, values, signatures, calldatas, description, 0); + } + + /** + * @notice Function used to propose a new proposal. Sender and signers must have delegates above the proposal threshold + * Signers are regarded as co-proposers, and therefore have the ability to cancel the proposal at any time. + * @param proposerSignatures Array of signers who have signed the proposal and their signatures. + * @dev The signatures follow EIP-712. See `PROPOSAL_TYPEHASH` in NounsDAOProposals.sol + * @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 + * @param clientId The ID of the client that faciliated posting the proposal onchain + * @return uint256 Proposal id of new proposal + */ + function proposeBySigs( + ProposerSignature[] memory proposerSignatures, + address[] memory targets, + uint256[] memory values, + string[] memory signatures, + bytes[] memory calldatas, + string memory description, + uint32 clientId + ) public returns (uint256) { return ds.proposeBySigs( proposerSignatures, - NounsDAOV3Proposals.ProposalTxs(targets, values, signatures, calldatas), - description + NounsDAOProposals.ProposalTxs(targets, values, signatures, calldatas), + description, + clientId ); } @@ -327,7 +404,7 @@ contract NounsDAOLogicV3 is NounsDAOStorageV3, NounsDAOEventsV3 { * Requires the original signers to sign the update. * @param proposalId Proposal's id * @param proposerSignatures Array of signers who have signed the proposal and their signatures. - * @dev The signatures follow EIP-712. See `UPDATE_PROPOSAL_TYPEHASH` in NounsDAOV3Proposals.sol + * @dev The signatures follow EIP-712. See `UPDATE_PROPOSAL_TYPEHASH` in NounsDAOProposals.sol * @param targets Updated target addresses for proposal calls * @param values Updated eth values for proposal calls * @param signatures Updated function signatures for proposal calls @@ -348,7 +425,7 @@ contract NounsDAOLogicV3 is NounsDAOStorageV3, NounsDAOEventsV3 { ds.updateProposalBySigs( proposalId, proposerSignatures, - NounsDAOV3Proposals.ProposalTxs(targets, values, signatures, calldatas), + NounsDAOProposals.ProposalTxs(targets, values, signatures, calldatas), description, updateMessage ); @@ -370,15 +447,6 @@ contract NounsDAOLogicV3 is NounsDAOStorageV3, NounsDAOEventsV3 { ds.execute(proposalId); } - /** - * @notice Executes a queued proposal on timelockV1 if eta has passed - * This is only required for proposal that were queued on timelockV1, but before the upgrade to DAO V3. - * These proposals will not have the `executeOnTimelockV1` bool turned on. - */ - function executeOnTimelockV1(uint256 proposalId) external { - ds.executeOnTimelockV1(proposalId); - } - /** * @notice Cancels a proposal only if sender is the proposer or a signer, or proposer & signers voting power * dropped below proposal threshold @@ -405,7 +473,9 @@ contract NounsDAOLogicV3 is NounsDAOStorageV3, NounsDAOEventsV3 { * @return signatures * @return calldatas */ - function getActions(uint256 proposalId) + function getActions( + uint256 proposalId + ) external view returns ( @@ -434,7 +504,7 @@ contract NounsDAOLogicV3 is NounsDAOStorageV3, NounsDAOEventsV3 { * @param proposalId the proposal id to get the data for * @return A `ProposalCondensed` struct with the proposal data, backwards compatible with V1 and V2 */ - function proposals(uint256 proposalId) external view returns (NounsDAOStorageV2.ProposalCondensed memory) { + function proposals(uint256 proposalId) external view returns (NounsDAOTypes.ProposalCondensedV2 memory) { return ds.proposals(proposalId); } @@ -445,16 +515,45 @@ contract NounsDAOLogicV3 is NounsDAOStorageV3, NounsDAOEventsV3 { * @return A `ProposalCondensed` struct with the proposal data, not backwards compatible as it contains additional values * like `objectionPeriodEndBlock` and `signers` */ - function proposalsV3(uint256 proposalId) external view returns (ProposalCondensed memory) { + function proposalsV3(uint256 proposalId) external view returns (ProposalCondensedV3 memory) { return ds.proposalsV3(proposalId); } + /** + * @notice Get a range of proposals, in the format of a smaller struct tailored to client incentives rewards. + * @param firstProposalId the id of the first proposal to get the data for + * @param lastProposalId the id of the last proposal to get the data for + * @param proposalEligibilityQuorumBps filters proposals with for-votes/total-supply higher than this quorum + * @param excludeCanceled if true, excludes canceled proposals + * @param requireVotingEnded if true, reverts if one of the proposals hasn't finished voting yet + * @param votingClientIds the ids of the clients that facilitated votes on the proposals + * @return An array of `ProposalForRewards` structs with the proposal data + */ + function proposalDataForRewards( + uint256 firstProposalId, + uint256 lastProposalId, + uint16 proposalEligibilityQuorumBps, + bool excludeCanceled, + bool requireVotingEnded, + uint32[] calldata votingClientIds + ) external view returns (ProposalForRewards[] memory) { + return + ds.proposalDataForRewards( + firstProposalId, + lastProposalId, + proposalEligibilityQuorumBps, + excludeCanceled, + requireVotingEnded, + votingClientIds + ); + } + /** * @notice Current proposal threshold using Noun Total Supply * Differs from `GovernerBravo` which uses fixed amount */ function proposalThreshold() public view returns (uint256) { - return ds.proposalThreshold(ds.adjustedTotalSupply()); + return ds.proposalThreshold(adjustedTotalSupply()); } /** @@ -504,11 +603,7 @@ contract NounsDAOLogicV3 is NounsDAOStorageV3, NounsDAOEventsV3 { * @param proposalIds array of proposal ids which are the reason for wanting to fork. This will only be used to emit event. * @param reason the reason for want to fork. This will only be used to emit event. */ - function joinFork( - uint256[] calldata tokenIds, - uint256[] calldata proposalIds, - string calldata reason - ) external { + function joinFork(uint256[] calldata tokenIds, uint256[] calldata proposalIds, string calldata reason) external { ds.joinFork(tokenIds, proposalIds, reason); } @@ -536,7 +631,7 @@ contract NounsDAOLogicV3 is NounsDAOStorageV3, NounsDAOEventsV3 { * escrow after it has closed. * This is used when calculating proposal threshold, quorum, fork threshold & treasury split. */ - function adjustedTotalSupply() external view returns (uint256) { + function adjustedTotalSupply() public view returns (uint256) { return ds.adjustedTotalSupply(); } @@ -588,7 +683,7 @@ contract NounsDAOLogicV3 is NounsDAOStorageV3, NounsDAOEventsV3 { * @dev Reentrancy is defended against in `castVoteInternal` at the `receipt.hasVoted == false` require statement. */ function castRefundableVote(uint256 proposalId, uint8 support) external { - ds.castRefundableVote(proposalId, support); + ds.castRefundableVote(proposalId, support, 0); } /** @@ -599,274 +694,72 @@ contract NounsDAOLogicV3 is NounsDAOStorageV3, NounsDAOEventsV3 { * 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 + * @param clientId The ID of the client that faciliated posting the vote onchain * @dev Reentrancy is defended against in `castVoteInternal` at the `receipt.hasVoted == false` require statement. */ - function castRefundableVoteWithReason( - uint256 proposalId, - uint8 support, - string calldata reason - ) external { - ds.castRefundableVoteWithReason(proposalId, support, reason); + function castRefundableVote(uint256 proposalId, uint8 support, uint32 clientId) external { + ds.castRefundableVote(proposalId, support, clientId); } /** - * @notice Cast a vote for a proposal with a reason + * @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 castVoteWithReason( - uint256 proposalId, - uint8 support, - string calldata reason - ) external { - ds.castVoteWithReason(proposalId, support, reason); + function castRefundableVoteWithReason(uint256 proposalId, uint8 support, string calldata reason) public { + ds.castRefundableVoteWithReason(proposalId, support, reason, 0); } /** - * @notice Cast a vote for a proposal by signature - * @dev External function that accepts EIP-712 signatures for voting on proposals. + * @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 + * @param clientId The ID of the client that faciliated posting the vote onchain + * @dev Reentrancy is defended against in `castVoteInternal` at the `receipt.hasVoted == false` require statement. */ - function castVoteBySig( + function castRefundableVoteWithReason( uint256 proposalId, uint8 support, - uint8 v, - bytes32 r, - bytes32 s - ) external { - ds.castVoteBySig(proposalId, support, v, r, s); - } - - /** - * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ - * ADMIN - * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ - */ - - /** - * @notice Admin function for setting the voting delay. Best to set voting delay to at least a few days, to give - * voters time to make sense of proposals, e.g. 21,600 blocks which should be at least 3 days. - * @param newVotingDelay new voting delay, in blocks - */ - function _setVotingDelay(uint256 newVotingDelay) external { - ds._setVotingDelay(newVotingDelay); - } - - /** - * @notice Admin function for setting the voting period - * @param newVotingPeriod new voting period, in blocks - */ - function _setVotingPeriod(uint256 newVotingPeriod) external { - ds._setVotingPeriod(newVotingPeriod); - } - - /** - * @notice Admin function for setting the proposal threshold basis points - * @dev newProposalThresholdBPS must be in [`MIN_PROPOSAL_THRESHOLD_BPS`,`MAX_PROPOSAL_THRESHOLD_BPS`] - * @param newProposalThresholdBPS new proposal threshold - */ - function _setProposalThresholdBPS(uint256 newProposalThresholdBPS) external { - ds._setProposalThresholdBPS(newProposalThresholdBPS); - } - - /** - * @notice Admin function for setting the objection period duration - * @param newObjectionPeriodDurationInBlocks new objection period duration, in blocks - */ - function _setObjectionPeriodDurationInBlocks(uint32 newObjectionPeriodDurationInBlocks) external { - ds._setObjectionPeriodDurationInBlocks(newObjectionPeriodDurationInBlocks); - } - - /** - * @notice Admin function for setting the objection period last minute window - * @param newLastMinuteWindowInBlocks new objection period last minute window, in blocks - */ - function _setLastMinuteWindowInBlocks(uint32 newLastMinuteWindowInBlocks) external { - ds._setLastMinuteWindowInBlocks(newLastMinuteWindowInBlocks); - } - - /** - * @notice Admin function for setting the proposal updatable period - * @param newProposalUpdatablePeriodInBlocks the new proposal updatable period, in blocks - */ - function _setProposalUpdatablePeriodInBlocks(uint32 newProposalUpdatablePeriodInBlocks) external { - ds._setProposalUpdatablePeriodInBlocks(newProposalUpdatablePeriodInBlocks); - } - - /** - * @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 { - ds._setPendingAdmin(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 { - ds._acceptAdmin(); - } - - /** - * @notice Begins transition of vetoer. The newPendingVetoer must call _acceptVetoer to finalize the transfer. - * @param newPendingVetoer New Pending Vetoer - */ - function _setPendingVetoer(address newPendingVetoer) public { - ds._setPendingVetoer(newPendingVetoer); - } - - /** - * @notice Called by the pendingVetoer to accept role and update vetoer - */ - function _acceptVetoer() external { - ds._acceptVetoer(); - } - - /** - * @notice Burns veto priviledges - * @dev Vetoer function destroying veto power forever - */ - function _burnVetoPower() public { - ds._burnVetoPower(); - } - - /** - * @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 { - ds._setMinQuorumVotesBPS(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 { - ds._setMaxQuorumVotesBPS(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 { - ds._setQuorumCoefficient(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 + string calldata reason, + uint32 clientId ) public { - ds._setDynamicQuorumParams(newMinQuorumVotesBPS, newMaxQuorumVotesBPS, newQuorumCoefficient); - } - - /** - * @notice Withdraws all the ETH in the contract. This is callable only by the admin (timelock). - */ - function _withdraw() external returns (uint256, bool) { - return ds._withdraw(); - } - - /** - * @notice Admin function for setting the fork period - * @param newForkPeriod the new fork proposal period, in seconds - */ - function _setForkPeriod(uint256 newForkPeriod) external { - ds._setForkPeriod(newForkPeriod); - } - - /** - * @notice Admin function for setting the fork threshold - * @param newForkThresholdBPS the new fork proposal threshold, in basis points - */ - function _setForkThresholdBPS(uint256 newForkThresholdBPS) external { - ds._setForkThresholdBPS(newForkThresholdBPS); + ds.castRefundableVoteWithReason(proposalId, support, reason, clientId); } /** - * @notice Admin function for setting the proposal id at which vote snapshots start using the voting start block - * instead of the proposal creation block. - * Sets it to the next proposal id. - */ - function _setVoteSnapshotBlockSwitchProposalId() external { - ds._setVoteSnapshotBlockSwitchProposalId(); - } - - /** - * @notice Admin function for setting the fork DAO deployer contract - */ - function _setForkDAODeployer(address newForkDAODeployer) external { - ds._setForkDAODeployer(newForkDAODeployer); - } - - /** - * @notice Admin function for setting the ERC20 tokens that are used when splitting funds to a fork - */ - function _setErc20TokensToIncludeInFork(address[] calldata erc20tokens) external { - ds._setErc20TokensToIncludeInFork(erc20tokens); - } - - /** - * @notice Admin function for setting the fork escrow contract + * @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 _setForkEscrow(address newForkEscrow) external { - ds._setForkEscrow(newForkEscrow); + function castVoteWithReason(uint256 proposalId, uint8 support, string calldata reason) external { + ds.castVoteWithReason(proposalId, support, reason); } /** - * @notice Admin function for setting the fork related parameters - * @param forkEscrow_ the fork escrow contract - * @param forkDAODeployer_ the fork dao deployer contract - * @param erc20TokensToIncludeInFork_ the ERC20 tokens used when splitting funds to a fork - * @param forkPeriod_ the period during which it's possible to join a fork after exeuction - * @param forkThresholdBPS_ the threshold required of escrowed nouns in order to execute a fork + * @notice Cast a vote for a proposal by signature + * @dev External function that accepts EIP-712 signatures for voting on proposals. */ - function _setForkParams( - address forkEscrow_, - address forkDAODeployer_, - address[] calldata erc20TokensToIncludeInFork_, - uint256 forkPeriod_, - uint256 forkThresholdBPS_ - ) external { - ds._setForkEscrow(forkEscrow_); - ds._setForkDAODeployer(forkDAODeployer_); - ds._setErc20TokensToIncludeInFork(erc20TokensToIncludeInFork_); - ds._setForkPeriod(forkPeriod_); - ds._setForkThresholdBPS(forkThresholdBPS_); + function castVoteBySig(uint256 proposalId, uint8 support, uint8 v, bytes32 r, bytes32 s) external { + ds.castVoteBySig(proposalId, support, v, r, s); } /** - * @notice Admin function for setting the timelocks and admin - * @param newTimelock the new timelock contract - * @param newTimelockV1 the new timelockV1 contract - * @param newAdmin the new admin address + * @dev All other calls are called via NounsDAOAdmin */ - function _setTimelocksAndAdmin( - address newTimelock, - address newTimelockV1, - address newAdmin - ) external { - ds._setTimelocksAndAdmin(newTimelock, newTimelockV1, newAdmin); + fallback(bytes calldata) external payable returns (bytes memory) { + return Address.functionDelegateCall(address(NounsDAOAdmin), msg.data); } /** @@ -900,7 +793,7 @@ contract NounsDAOLogicV3 is NounsDAOStorageV3, NounsDAOEventsV3 { uint256 adjustedTotalSupply_, DynamicQuorumParams memory params ) public pure returns (uint256) { - return NounsDAOV3DynamicQuorum.dynamicQuorumVotes(againstVotes, adjustedTotalSupply_, params); + return NounsDAODynamicQuorum.dynamicQuorumVotes(againstVotes, adjustedTotalSupply_, params); } /** @@ -948,6 +841,10 @@ contract NounsDAOLogicV3 is NounsDAOStorageV3, NounsDAOEventsV3 { * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ */ + function admin() public view returns (address) { + return ds.admin; + } + function vetoer() public view returns (address) { return ds.vetoer; } diff --git a/packages/nouns-contracts/contracts/governance/NounsDAOV3Proposals.sol b/packages/nouns-contracts/contracts/governance/NounsDAOProposals.sol similarity index 70% rename from packages/nouns-contracts/contracts/governance/NounsDAOV3Proposals.sol rename to packages/nouns-contracts/contracts/governance/NounsDAOProposals.sol index 7de3a3f4c8..0055ceb549 100644 --- a/packages/nouns-contracts/contracts/governance/NounsDAOV3Proposals.sol +++ b/packages/nouns-contracts/contracts/governance/NounsDAOProposals.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-3.0 -/// @title Library for NounsDAOLogicV3 contract containing the proposal lifecycle code +/// @title Library for Nouns DAO Logic containing the proposal lifecycle code /********************************* * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ * @@ -18,15 +18,15 @@ pragma solidity ^0.8.19; import './NounsDAOInterfaces.sol'; -import { NounsDAOV3DynamicQuorum } from './NounsDAOV3DynamicQuorum.sol'; -import { NounsDAOV3Fork } from './fork/NounsDAOV3Fork.sol'; +import { NounsDAODynamicQuorum } from './NounsDAODynamicQuorum.sol'; +import { NounsDAOFork } from './fork/NounsDAOFork.sol'; import { SignatureChecker } from '../external/openzeppelin/SignatureChecker.sol'; import { ECDSA } from '../external/openzeppelin/ECDSA.sol'; import { SafeCast } from '@openzeppelin/contracts/utils/math/SafeCast.sol'; -library NounsDAOV3Proposals { - using NounsDAOV3DynamicQuorum for NounsDAOStorageV3.StorageV3; - using NounsDAOV3Fork for NounsDAOStorageV3.StorageV3; +library NounsDAOProposals { + using NounsDAODynamicQuorum for NounsDAOTypes.Storage; + using NounsDAOFork for NounsDAOTypes.Storage; error CantCancelProposalAtFinalState(); error ProposalInfoArityMismatch(); @@ -47,86 +47,6 @@ library NounsDAOV3Proposals { error CantVetoExecutedProposal(); error VotesBelowProposalThreshold(); - /// @notice An event emitted when a proposal has been vetoed by vetoAddress - event ProposalVetoed(uint256 id); - - /// @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 - /// @dev V3 adds `signers`, `updatePeriodEndBlock` compared to the V1/V2 event. - event ProposalCreatedWithRequirements( - uint256 id, - address proposer, - address[] signers, - address[] targets, - uint256[] values, - string[] signatures, - bytes[] calldatas, - uint256 startBlock, - uint256 endBlock, - uint256 updatePeriodEndBlock, - uint256 proposalThreshold, - uint256 quorumVotes, - string description - ); - - /// @notice Emitted when a proposal is created to be executed on timelockV1 - event ProposalCreatedOnTimelockV1(uint256 id); - - /// @notice Emitted when a proposal is updated - event ProposalUpdated( - uint256 indexed id, - address indexed proposer, - address[] targets, - uint256[] values, - string[] signatures, - bytes[] calldatas, - string description, - string updateMessage - ); - - /// @notice Emitted when a proposal's transactions are updated - event ProposalTransactionsUpdated( - uint256 indexed id, - address indexed proposer, - address[] targets, - uint256[] values, - string[] signatures, - bytes[] calldatas, - string updateMessage - ); - - /// @notice Emitted when a proposal's description is updated - event ProposalDescriptionUpdated( - uint256 indexed id, - address indexed proposer, - string description, - string updateMessage - ); - - /// @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 canceled - event ProposalCanceled(uint256 id); - - /// @notice Emitted when someone cancels a signature - event SignatureCancelled(address indexed signer, bytes sig); - // Created to solve stack-too-deep errors struct ProposalTxs { address[] targets; @@ -155,12 +75,14 @@ library NounsDAOV3Proposals { * @notice Function used to propose a new proposal. Sender must have delegates above the proposal threshold * @param txs Target addresses, eth values, function signatures and calldatas for proposal calls * @param description String description of the proposal + * @param clientId The ID of the client that faciliated posting the proposal onchain * @return Proposal id of new proposal */ function propose( - NounsDAOStorageV3.StorageV3 storage ds, + NounsDAOTypes.Storage storage ds, ProposalTxs memory txs, - string memory description + string memory description, + uint32 clientId ) internal returns (uint256) { uint256 adjustedTotalSupply = ds.adjustedTotalSupply(); uint256 proposalThreshold_ = checkPropThreshold( @@ -171,17 +93,26 @@ library NounsDAOV3Proposals { checkProposalTxs(txs); checkNoActiveProp(ds, msg.sender); - uint256 proposalId = ds.proposalCount = ds.proposalCount + 1; - NounsDAOStorageV3.Proposal storage newProposal = createNewProposal( + ds.proposalCount = ds.proposalCount + 1; + uint32 proposalId = SafeCast.toUint32(ds.proposalCount); + NounsDAOTypes.Proposal storage newProposal = createNewProposal( ds, proposalId, proposalThreshold_, adjustedTotalSupply, - txs + txs, + clientId ); ds.latestProposalIds[msg.sender] = proposalId; - emitNewPropEvents(newProposal, new address[](0), ds.minQuorumVotes(adjustedTotalSupply), txs, description); + emitNewPropEvents( + newProposal, + new address[](0), + ds.minQuorumVotes(adjustedTotalSupply), + txs, + description, + clientId + ); return proposalId; } @@ -192,51 +123,63 @@ library NounsDAOV3Proposals { * is still holding funds or has special permissions to execute on certain contracts. * @param txs Target addresses, eth values, function signatures and calldatas for proposal calls * @param description String description of the proposal + * @param clientId The ID of the client that faciliated posting the proposal onchain * @return uint256 Proposal id of new proposal */ function proposeOnTimelockV1( - NounsDAOStorageV3.StorageV3 storage ds, + NounsDAOTypes.Storage storage ds, ProposalTxs memory txs, - string memory description + string memory description, + uint32 clientId ) internal returns (uint256) { - uint256 newProposalId = propose(ds, txs, description); + uint256 newProposalId = propose(ds, txs, description, clientId); - NounsDAOStorageV3.Proposal storage newProposal = ds._proposals[newProposalId]; + NounsDAOTypes.Proposal storage newProposal = ds._proposals[newProposalId]; newProposal.executeOnTimelockV1 = true; - emit ProposalCreatedOnTimelockV1(newProposalId); + emit NounsDAOEventsV3.ProposalCreatedOnTimelockV1(newProposalId); return newProposalId; } + struct ProposalTemp { + uint32 proposalId; + uint256 adjustedTotalSupply; + uint256 propThreshold; + } + /** * @notice Function used to propose a new proposal. Sender and signers must have delegates above the proposal threshold * @param proposerSignatures Array of signers who have signed the proposal and their signatures. - * @dev The signatures follow EIP-712. See `PROPOSAL_TYPEHASH` in NounsDAOV3Proposals.sol + * @dev The signatures follow EIP-712. See `PROPOSAL_TYPEHASH` in NounsDAOProposals.sol * @param txs Target addresses, eth values, function signatures and calldatas for proposal calls * @param description String description of the proposal + * @param clientId The ID of the client that faciliated posting the proposal onchain * @return uint256 Proposal id of new proposal */ function proposeBySigs( - NounsDAOStorageV3.StorageV3 storage ds, - NounsDAOStorageV3.ProposerSignature[] memory proposerSignatures, + NounsDAOTypes.Storage storage ds, + NounsDAOTypes.ProposerSignature[] memory proposerSignatures, ProposalTxs memory txs, - string memory description + string memory description, + uint32 clientId ) external returns (uint256) { if (proposerSignatures.length == 0) revert MustProvideSignatures(); checkProposalTxs(txs); - uint256 proposalId = ds.proposalCount = ds.proposalCount + 1; - - uint256 adjustedTotalSupply = ds.adjustedTotalSupply(); - uint256 propThreshold = proposalThreshold(ds, adjustedTotalSupply); + ProposalTemp memory temp; + ds.proposalCount = ds.proposalCount + 1; + temp.proposalId = SafeCast.toUint32(ds.proposalCount); + temp.adjustedTotalSupply = ds.adjustedTotalSupply(); + temp.propThreshold = proposalThreshold(ds, temp.adjustedTotalSupply); - NounsDAOStorageV3.Proposal storage newProposal = createNewProposal( + NounsDAOTypes.Proposal storage newProposal = createNewProposal( ds, - proposalId, - propThreshold, - adjustedTotalSupply, - txs + temp.proposalId, + temp.propThreshold, + temp.adjustedTotalSupply, + txs, + clientId ); // important that the proposal is created before the verification call in order to ensure @@ -246,16 +189,23 @@ library NounsDAOV3Proposals { proposerSignatures, txs, description, - proposalId + temp.proposalId ); if (signers.length == 0) revert MustProvideSignatures(); - if (votes <= propThreshold) revert VotesBelowProposalThreshold(); + if (votes <= temp.propThreshold) revert VotesBelowProposalThreshold(); newProposal.signers = signers; - emitNewPropEvents(newProposal, signers, ds.minQuorumVotes(adjustedTotalSupply), txs, description); + emitNewPropEvents( + newProposal, + signers, + ds.minQuorumVotes(temp.adjustedTotalSupply), + txs, + description, + clientId + ); - return proposalId; + return temp.proposalId; } /** @@ -267,11 +217,11 @@ library NounsDAOV3Proposals { * not be invalidated. * @param sig The signature to cancel */ - function cancelSig(NounsDAOStorageV3.StorageV3 storage ds, bytes calldata sig) external { + function cancelSig(NounsDAOTypes.Storage storage ds, bytes calldata sig) external { bytes32 sigHash = keccak256(sig); ds.cancelledSigs[msg.sender][sigHash] = true; - emit SignatureCancelled(msg.sender, sig); + emit NounsDAOEventsV3.SignatureCancelled(msg.sender, sig); } /** @@ -286,7 +236,7 @@ library NounsDAOV3Proposals { * @param updateMessage Short message to explain the update */ function updateProposal( - NounsDAOStorageV3.StorageV3 storage ds, + NounsDAOTypes.Storage storage ds, uint256 proposalId, address[] memory targets, uint256[] memory values, @@ -297,7 +247,7 @@ library NounsDAOV3Proposals { ) external { updateProposalTransactionsInternal(ds, proposalId, targets, values, signatures, calldatas); - emit ProposalUpdated( + emit NounsDAOEventsV3.ProposalUpdated( proposalId, msg.sender, targets, @@ -319,7 +269,7 @@ library NounsDAOV3Proposals { * @param updateMessage Short message to explain the update */ function updateProposalTransactions( - NounsDAOStorageV3.StorageV3 storage ds, + NounsDAOTypes.Storage storage ds, uint256 proposalId, address[] memory targets, uint256[] memory values, @@ -329,11 +279,19 @@ library NounsDAOV3Proposals { ) external { updateProposalTransactionsInternal(ds, proposalId, targets, values, signatures, calldatas); - emit ProposalTransactionsUpdated(proposalId, msg.sender, targets, values, signatures, calldatas, updateMessage); + emit NounsDAOEventsV3.ProposalTransactionsUpdated( + proposalId, + msg.sender, + targets, + values, + signatures, + calldatas, + updateMessage + ); } function updateProposalTransactionsInternal( - NounsDAOStorageV3.StorageV3 storage ds, + NounsDAOTypes.Storage storage ds, uint256 proposalId, address[] memory targets, uint256[] memory values, @@ -342,7 +300,7 @@ library NounsDAOV3Proposals { ) internal { checkProposalTxs(ProposalTxs(targets, values, signatures, calldatas)); - NounsDAOStorageV3.Proposal storage proposal = ds._proposals[proposalId]; + NounsDAOTypes.Proposal storage proposal = ds._proposals[proposalId]; checkProposalUpdatable(ds, proposalId, proposal); proposal.targets = targets; @@ -358,15 +316,15 @@ library NounsDAOV3Proposals { * @param updateMessage Short message to explain the update */ function updateProposalDescription( - NounsDAOStorageV3.StorageV3 storage ds, + NounsDAOTypes.Storage storage ds, uint256 proposalId, string calldata description, string calldata updateMessage ) external { - NounsDAOStorageV3.Proposal storage proposal = ds._proposals[proposalId]; + NounsDAOTypes.Proposal storage proposal = ds._proposals[proposalId]; checkProposalUpdatable(ds, proposalId, proposal); - emit ProposalDescriptionUpdated(proposalId, msg.sender, description, updateMessage); + emit NounsDAOEventsV3.ProposalDescriptionUpdated(proposalId, msg.sender, description, updateMessage); } /** @@ -375,15 +333,15 @@ library NounsDAOV3Proposals { * Requires the original signers to sign the update. * @param proposalId Proposal's id * @param proposerSignatures Array of signers who have signed the proposal and their signatures. - * @dev The signatures follow EIP-712. See `UPDATE_PROPOSAL_TYPEHASH` in NounsDAOV3Proposals.sol + * @dev The signatures follow EIP-712. See `UPDATE_PROPOSAL_TYPEHASH` in NounsDAOProposals.sol * @param txs Updated transactions for the proposal * @param description Updated description of the proposal * @param updateMessage Short message to explain the update */ function updateProposalBySigs( - NounsDAOStorageV3.StorageV3 storage ds, + NounsDAOTypes.Storage storage ds, uint256 proposalId, - NounsDAOStorageV3.ProposerSignature[] memory proposerSignatures, + NounsDAOTypes.ProposerSignature[] memory proposerSignatures, ProposalTxs memory txs, string memory description, string memory updateMessage @@ -393,8 +351,8 @@ library NounsDAOV3Proposals { // this problem doesn't exist in the propose function because we check for prop threshold there if (proposerSignatures.length == 0) revert MustProvideSignatures(); - NounsDAOStorageV3.Proposal storage proposal = ds._proposals[proposalId]; - if (stateInternal(ds, proposalId) != NounsDAOStorageV3.ProposalState.Updatable) + NounsDAOTypes.Proposal storage proposal = ds._proposals[proposalId]; + if (stateInternal(ds, proposalId) != NounsDAOTypes.ProposalState.Updatable) revert CanOnlyEditUpdatableProposals(); if (msg.sender != proposal.proposer) revert OnlyProposerCanEdit(); @@ -419,7 +377,7 @@ library NounsDAOV3Proposals { proposal.signatures = txs.signatures; proposal.calldatas = txs.calldatas; - emit ProposalUpdated( + emit NounsDAOEventsV3.ProposalUpdated( proposalId, msg.sender, txs.targets, @@ -435,12 +393,12 @@ library NounsDAOV3Proposals { * @notice Queues a proposal of state succeeded * @param proposalId The id of the proposal to queue */ - function queue(NounsDAOStorageV3.StorageV3 storage ds, uint256 proposalId) external { + function queue(NounsDAOTypes.Storage storage ds, uint256 proposalId) external { require( - stateInternal(ds, proposalId) == NounsDAOStorageV3.ProposalState.Succeeded, + stateInternal(ds, proposalId) == NounsDAOTypes.ProposalState.Succeeded, 'NounsDAO::queue: proposal can only be queued if it is succeeded' ); - NounsDAOStorageV3.Proposal storage proposal = ds._proposals[proposalId]; + NounsDAOTypes.Proposal storage proposal = ds._proposals[proposalId]; INounsDAOExecutor timelock = getProposalTimelock(ds, proposal); uint256 eta = block.timestamp + timelock.delay(); for (uint256 i = 0; i < proposal.targets.length; i++) { @@ -454,7 +412,7 @@ library NounsDAOV3Proposals { ); } proposal.eta = eta; - emit ProposalQueued(proposalId, eta); + emit NounsDAOEventsV3.ProposalQueued(proposalId, eta); } function queueOrRevertInternal( @@ -476,29 +434,19 @@ library NounsDAOV3Proposals { * @notice Executes a queued proposal if eta has passed * @param proposalId The id of the proposal to execute */ - function execute(NounsDAOStorageV3.StorageV3 storage ds, uint256 proposalId) external { - NounsDAOStorageV3.Proposal storage proposal = ds._proposals[proposalId]; + function execute(NounsDAOTypes.Storage storage ds, uint256 proposalId) external { + NounsDAOTypes.Proposal storage proposal = ds._proposals[proposalId]; INounsDAOExecutor timelock = getProposalTimelock(ds, proposal); executeInternal(ds, proposal, timelock); } - /** - * @notice Executes a queued proposal on timelockV1 if eta has passed - * This is only required for proposal that were queued on timelockV1, but before the upgrade to DAO V3. - * These proposals will not have the `executeOnTimelockV1` bool turned on. - */ - function executeOnTimelockV1(NounsDAOStorageV3.StorageV3 storage ds, uint256 proposalId) external { - NounsDAOStorageV3.Proposal storage proposal = ds._proposals[proposalId]; - executeInternal(ds, proposal, ds.timelockV1); - } - function executeInternal( - NounsDAOStorageV3.StorageV3 storage ds, - NounsDAOStorageV3.Proposal storage proposal, + NounsDAOTypes.Storage storage ds, + NounsDAOTypes.Proposal storage proposal, INounsDAOExecutor timelock ) internal { require( - stateInternal(ds, proposal.id) == NounsDAOStorageV3.ProposalState.Queued, + stateInternal(ds, proposal.id) == NounsDAOTypes.ProposalState.Queued, 'NounsDAO::execute: proposal can only be executed if it is queued' ); if (ds.isForkPeriodActive()) revert CannotExecuteDuringForkingPeriod(); @@ -514,14 +462,13 @@ library NounsDAOV3Proposals { proposal.eta ); } - emit ProposalExecuted(proposal.id); + emit NounsDAOEventsV3.ProposalExecuted(proposal.id); } - function getProposalTimelock(NounsDAOStorageV3.StorageV3 storage ds, NounsDAOStorageV3.Proposal storage proposal) - internal - view - returns (INounsDAOExecutor) - { + function getProposalTimelock( + NounsDAOTypes.Storage storage ds, + NounsDAOTypes.Proposal storage proposal + ) internal view returns (INounsDAOExecutor) { if (proposal.executeOnTimelockV1) { return ds.timelockV1; } else { @@ -533,7 +480,7 @@ library NounsDAOV3Proposals { * @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(NounsDAOStorageV3.StorageV3 storage ds, uint256 proposalId) external { + function veto(NounsDAOTypes.Storage storage ds, uint256 proposalId) external { if (ds.vetoer == address(0)) { revert VetoerBurned(); } @@ -542,11 +489,11 @@ library NounsDAOV3Proposals { revert VetoerOnly(); } - if (stateInternal(ds, proposalId) == NounsDAOStorageV3.ProposalState.Executed) { + if (stateInternal(ds, proposalId) == NounsDAOTypes.ProposalState.Executed) { revert CantVetoExecutedProposal(); } - NounsDAOStorageV3.Proposal storage proposal = ds._proposals[proposalId]; + NounsDAOTypes.Proposal storage proposal = ds._proposals[proposalId]; proposal.vetoed = true; INounsDAOExecutor timelock = getProposalTimelock(ds, proposal); @@ -560,7 +507,7 @@ library NounsDAOV3Proposals { ); } - emit ProposalVetoed(proposalId); + emit NounsDAOEventsV3.ProposalVetoed(proposalId); } /** @@ -568,19 +515,19 @@ library NounsDAOV3Proposals { * dropped below proposal threshold * @param proposalId The id of the proposal to cancel */ - function cancel(NounsDAOStorageV3.StorageV3 storage ds, uint256 proposalId) external { - NounsDAOStorageV3.ProposalState proposalState = stateInternal(ds, proposalId); + function cancel(NounsDAOTypes.Storage storage ds, uint256 proposalId) external { + NounsDAOTypes.ProposalState proposalState = stateInternal(ds, proposalId); if ( - proposalState == NounsDAOStorageV3.ProposalState.Canceled || - proposalState == NounsDAOStorageV3.ProposalState.Defeated || - proposalState == NounsDAOStorageV3.ProposalState.Expired || - proposalState == NounsDAOStorageV3.ProposalState.Executed || - proposalState == NounsDAOStorageV3.ProposalState.Vetoed + proposalState == NounsDAOTypes.ProposalState.Canceled || + proposalState == NounsDAOTypes.ProposalState.Defeated || + proposalState == NounsDAOTypes.ProposalState.Expired || + proposalState == NounsDAOTypes.ProposalState.Executed || + proposalState == NounsDAOTypes.ProposalState.Vetoed ) { revert CantCancelProposalAtFinalState(); } - NounsDAOStorageV3.Proposal storage proposal = ds._proposals[proposalId]; + NounsDAOTypes.Proposal storage proposal = ds._proposals[proposalId]; address proposer = proposal.proposer; NounsTokenLike nouns = ds.nouns; @@ -609,7 +556,7 @@ library NounsDAOV3Proposals { ); } - emit ProposalCanceled(proposalId); + emit NounsDAOEventsV3.ProposalCanceled(proposalId); } /** @@ -618,11 +565,10 @@ library NounsDAOV3Proposals { * @param proposalId The id of the proposal * @return Proposal state */ - function state(NounsDAOStorageV3.StorageV3 storage ds, uint256 proposalId) - public - view - returns (NounsDAOStorageV3.ProposalState) - { + function state( + NounsDAOTypes.Storage storage ds, + uint256 proposalId + ) public view returns (NounsDAOTypes.ProposalState) { return stateInternal(ds, proposalId); } @@ -633,36 +579,35 @@ library NounsDAOV3Proposals { * @param proposalId The id of the proposal * @return Proposal state */ - function stateInternal(NounsDAOStorageV3.StorageV3 storage ds, uint256 proposalId) - internal - view - returns (NounsDAOStorageV3.ProposalState) - { + function stateInternal( + NounsDAOTypes.Storage storage ds, + uint256 proposalId + ) internal view returns (NounsDAOTypes.ProposalState) { require(ds.proposalCount >= proposalId, 'NounsDAO::state: invalid proposal id'); - NounsDAOStorageV3.Proposal storage proposal = ds._proposals[proposalId]; + NounsDAOTypes.Proposal storage proposal = ds._proposals[proposalId]; if (proposal.vetoed) { - return NounsDAOStorageV3.ProposalState.Vetoed; + return NounsDAOTypes.ProposalState.Vetoed; } else if (proposal.canceled) { - return NounsDAOStorageV3.ProposalState.Canceled; + return NounsDAOTypes.ProposalState.Canceled; } else if (block.number <= proposal.updatePeriodEndBlock) { - return NounsDAOStorageV3.ProposalState.Updatable; + return NounsDAOTypes.ProposalState.Updatable; } else if (block.number <= proposal.startBlock) { - return NounsDAOStorageV3.ProposalState.Pending; + return NounsDAOTypes.ProposalState.Pending; } else if (block.number <= proposal.endBlock) { - return NounsDAOStorageV3.ProposalState.Active; + return NounsDAOTypes.ProposalState.Active; } else if (block.number <= proposal.objectionPeriodEndBlock) { - return NounsDAOStorageV3.ProposalState.ObjectionPeriod; + return NounsDAOTypes.ProposalState.ObjectionPeriod; } else if (isDefeated(ds, proposal)) { - return NounsDAOStorageV3.ProposalState.Defeated; + return NounsDAOTypes.ProposalState.Defeated; } else if (proposal.eta == 0) { - return NounsDAOStorageV3.ProposalState.Succeeded; + return NounsDAOTypes.ProposalState.Succeeded; } else if (proposal.executed) { - return NounsDAOStorageV3.ProposalState.Executed; + return NounsDAOTypes.ProposalState.Executed; } else if (block.timestamp >= proposal.eta + getProposalTimelock(ds, proposal).GRACE_PERIOD()) { - return NounsDAOStorageV3.ProposalState.Expired; + return NounsDAOTypes.ProposalState.Expired; } else { - return NounsDAOStorageV3.ProposalState.Queued; + return NounsDAOTypes.ProposalState.Queued; } } @@ -674,7 +619,10 @@ library NounsDAOV3Proposals { * @return signatures * @return calldatas */ - function getActions(NounsDAOStorageV3.StorageV3 storage ds, uint256 proposalId) + function getActions( + NounsDAOTypes.Storage storage ds, + uint256 proposalId + ) internal view returns ( @@ -684,7 +632,7 @@ library NounsDAOV3Proposals { bytes[] memory calldatas ) { - NounsDAOStorageV3.Proposal storage p = ds._proposals[proposalId]; + NounsDAOTypes.Proposal storage p = ds._proposals[proposalId]; return (p.targets, p.values, p.signatures, p.calldatas); } @@ -695,10 +643,10 @@ library NounsDAOV3Proposals { * @return The voting receipt */ function getReceipt( - NounsDAOStorageV3.StorageV3 storage ds, + NounsDAOTypes.Storage storage ds, uint256 proposalId, address voter - ) internal view returns (NounsDAOStorageV3.Receipt memory) { + ) internal view returns (NounsDAOTypes.Receipt memory) { return ds._proposals[proposalId].receipts[voter]; } @@ -708,14 +656,13 @@ library NounsDAOV3Proposals { * @param proposalId the proposal id to get the data for * @return A `ProposalCondensed` struct with the proposal data */ - function proposals(NounsDAOStorageV3.StorageV3 storage ds, uint256 proposalId) - external - view - returns (NounsDAOStorageV2.ProposalCondensed memory) - { - NounsDAOStorageV3.Proposal storage proposal = ds._proposals[proposalId]; + function proposals( + NounsDAOTypes.Storage storage ds, + uint256 proposalId + ) external view returns (NounsDAOTypes.ProposalCondensedV2 memory) { + NounsDAOTypes.Proposal storage proposal = ds._proposals[proposalId]; return - NounsDAOStorageV2.ProposalCondensed({ + NounsDAOTypes.ProposalCondensedV2({ id: proposal.id, proposer: proposal.proposer, proposalThreshold: proposal.proposalThreshold, @@ -740,14 +687,13 @@ library NounsDAOV3Proposals { * @param proposalId the proposal id to get the data for * @return A `ProposalCondensed` struct with the proposal data */ - function proposalsV3(NounsDAOStorageV3.StorageV3 storage ds, uint256 proposalId) - external - view - returns (NounsDAOStorageV3.ProposalCondensed memory) - { - NounsDAOStorageV3.Proposal storage proposal = ds._proposals[proposalId]; + function proposalsV3( + NounsDAOTypes.Storage storage ds, + uint256 proposalId + ) external view returns (NounsDAOTypes.ProposalCondensedV3 memory) { + NounsDAOTypes.Proposal storage proposal = ds._proposals[proposalId]; return - NounsDAOStorageV3.ProposalCondensed({ + NounsDAOTypes.ProposalCondensedV3({ id: proposal.id, proposer: proposal.proposer, proposalThreshold: proposal.proposalThreshold, @@ -770,23 +716,84 @@ library NounsDAOV3Proposals { }); } + struct Temp { + uint256 endBlock; + uint256 objectionPeriodEndBlock; + } + + function proposalDataForRewards( + NounsDAOTypes.Storage storage ds, + uint256 firstProposalId, + uint256 lastProposalId, + uint16 proposalEligibilityQuorumBps, + bool excludeCanceled, + bool requireVotingEnded, + uint32[] calldata votingClientIds + ) internal view returns (NounsDAOTypes.ProposalForRewards[] memory) { + require(lastProposalId >= firstProposalId, 'lastProposalId >= firstProposalId'); + uint256 numProposals = lastProposalId - firstProposalId + 1; + NounsDAOTypes.ProposalForRewards[] memory data = new NounsDAOTypes.ProposalForRewards[](numProposals); + + NounsDAOTypes.Proposal storage proposal; + uint256 i; + Temp memory t; + for (uint256 pid = firstProposalId; pid <= lastProposalId; ++pid) { + proposal = ds._proposals[pid]; + + if (excludeCanceled && proposal.canceled) continue; + + t.endBlock = proposal.endBlock; + t.objectionPeriodEndBlock = proposal.objectionPeriodEndBlock; + if (requireVotingEnded) { + uint256 votingEndBlock = max(t.endBlock, t.objectionPeriodEndBlock); + require(block.number > votingEndBlock, 'all proposals must be done with voting'); + } + + uint256 forVotes = proposal.forVotes; + uint256 totalSupply = proposal.totalSupply; + if (forVotes < (totalSupply * proposalEligibilityQuorumBps) / 10_000) continue; + + NounsDAOTypes.ClientVoteData[] memory c = new NounsDAOTypes.ClientVoteData[](votingClientIds.length); + for (uint256 j; j < votingClientIds.length; ++j) { + c[j] = proposal.voteClients[votingClientIds[j]]; + } + + data[i++] = NounsDAOTypes.ProposalForRewards({ + endBlock: t.endBlock, + objectionPeriodEndBlock: t.objectionPeriodEndBlock, + forVotes: forVotes, + againstVotes: proposal.againstVotes, + abstainVotes: proposal.abstainVotes, + totalSupply: totalSupply, + creationTimestamp: proposal.creationTimestamp, + clientId: proposal.clientId, + voteData: c + }); + } + + // change array size to the actually used size + assembly { + mstore(data, i) + } + + return data; + } + /** * @notice Current proposal threshold using Noun Total Supply * Differs from `GovernerBravo` which uses fixed amount */ - function proposalThreshold(NounsDAOStorageV3.StorageV3 storage ds, uint256 adjustedTotalSupply) - internal - view - returns (uint256) - { + function proposalThreshold( + NounsDAOTypes.Storage storage ds, + uint256 adjustedTotalSupply + ) internal view returns (uint256) { return bps2Uint(ds.proposalThresholdBPS, adjustedTotalSupply); } - function isDefeated(NounsDAOStorageV3.StorageV3 storage ds, NounsDAOStorageV3.Proposal storage proposal) - internal - view - returns (bool) - { + function isDefeated( + NounsDAOTypes.Storage storage ds, + NounsDAOTypes.Proposal storage proposal + ) internal view returns (bool) { uint256 forVotes = proposal.forVotes; return forVotes <= proposal.againstVotes || forVotes < ds.quorumVotes(proposal.id); } @@ -795,15 +802,15 @@ library NounsDAOV3Proposals { * @notice reverts if `proposer` is the proposer or signer of an active proposal. * This is a spam protection mechanism to limit the number of proposals each noun can back. */ - function checkNoActiveProp(NounsDAOStorageV3.StorageV3 storage ds, address proposer) internal view { + function checkNoActiveProp(NounsDAOTypes.Storage storage ds, address proposer) internal view { uint256 latestProposalId = ds.latestProposalIds[proposer]; if (latestProposalId != 0) { - NounsDAOStorageV3.ProposalState proposersLatestProposalState = stateInternal(ds, latestProposalId); + NounsDAOTypes.ProposalState proposersLatestProposalState = stateInternal(ds, latestProposalId); if ( - proposersLatestProposalState == NounsDAOStorageV3.ProposalState.ObjectionPeriod || - proposersLatestProposalState == NounsDAOStorageV3.ProposalState.Active || - proposersLatestProposalState == NounsDAOStorageV3.ProposalState.Pending || - proposersLatestProposalState == NounsDAOStorageV3.ProposalState.Updatable + proposersLatestProposalState == NounsDAOTypes.ProposalState.ObjectionPeriod || + proposersLatestProposalState == NounsDAOTypes.ProposalState.Active || + proposersLatestProposalState == NounsDAOTypes.ProposalState.Pending || + proposersLatestProposalState == NounsDAOTypes.ProposalState.Updatable ) revert ProposerAlreadyHasALiveProposal(); } } @@ -812,8 +819,8 @@ library NounsDAOV3Proposals { * @dev Extracted this function to fix the `Stack too deep` error `proposeBySigs` hit. */ function verifySignersCanBackThisProposalAndCountTheirVotes( - NounsDAOStorageV3.StorageV3 storage ds, - NounsDAOStorageV3.ProposerSignature[] memory proposerSignatures, + NounsDAOTypes.Storage storage ds, + NounsDAOTypes.ProposerSignature[] memory proposerSignatures, ProposalTxs memory txs, string memory description, uint256 proposalId @@ -878,29 +885,31 @@ library NounsDAOV3Proposals { } function checkProposalUpdatable( - NounsDAOStorageV3.StorageV3 storage ds, + NounsDAOTypes.Storage storage ds, uint256 proposalId, - NounsDAOStorageV3.Proposal storage proposal + NounsDAOTypes.Proposal storage proposal ) internal view { - if (stateInternal(ds, proposalId) != NounsDAOStorageV3.ProposalState.Updatable) + if (stateInternal(ds, proposalId) != NounsDAOTypes.ProposalState.Updatable) revert CanOnlyEditUpdatableProposals(); if (msg.sender != proposal.proposer) revert OnlyProposerCanEdit(); if (proposal.signers.length > 0) revert ProposerCannotUpdateProposalWithSigners(); } function createNewProposal( - NounsDAOStorageV3.StorageV3 storage ds, - uint256 proposalId, + NounsDAOTypes.Storage storage ds, + uint32 proposalId, uint256 proposalThreshold_, uint256 adjustedTotalSupply, - ProposalTxs memory txs - ) internal returns (NounsDAOStorageV3.Proposal storage newProposal) { + ProposalTxs memory txs, + uint32 clientId + ) internal returns (NounsDAOTypes.Proposal storage newProposal) { uint64 updatePeriodEndBlock = SafeCast.toUint64(block.number + ds.proposalUpdatablePeriodInBlocks); uint256 startBlock = updatePeriodEndBlock + ds.votingDelay; uint256 endBlock = startBlock + ds.votingPeriod; newProposal = ds._proposals[proposalId]; newProposal.id = proposalId; + newProposal.clientId = clientId; newProposal.proposer = msg.sender; newProposal.proposalThreshold = proposalThreshold_; newProposal.targets = txs.targets; @@ -910,19 +919,21 @@ library NounsDAOV3Proposals { newProposal.startBlock = startBlock; newProposal.endBlock = endBlock; newProposal.totalSupply = adjustedTotalSupply; - newProposal.creationBlock = SafeCast.toUint64(block.number); + newProposal.creationBlock = SafeCast.toUint32(block.number); + newProposal.creationTimestamp = SafeCast.toUint32(block.timestamp); newProposal.updatePeriodEndBlock = updatePeriodEndBlock; } function emitNewPropEvents( - NounsDAOStorageV3.Proposal storage newProposal, + NounsDAOTypes.Proposal storage newProposal, address[] memory signers, uint256 minQuorumVotes, ProposalTxs memory txs, - string memory description + string memory description, + uint32 clientId ) internal { /// @notice Maintains backwards compatibility with GovernorBravo events - emit ProposalCreated( + emit NounsDAOEventsV3.ProposalCreated( newProposal.id, msg.sender, txs.targets, @@ -937,25 +948,19 @@ library NounsDAOV3Proposals { /// @notice V1: Updated event with `proposalThreshold` and `quorumVotes` `minQuorumVotes` /// @notice V2: `quorumVotes` changed to `minQuorumVotes` /// @notice V3: Added signers and updatePeriodEndBlock - emit ProposalCreatedWithRequirements( + /// @notice V4: Removed data that's already emitted in `ProposalCreated`, added clientId + emit NounsDAOEventsV3.ProposalCreatedWithRequirements( newProposal.id, - msg.sender, signers, - txs.targets, - txs.values, - txs.signatures, - txs.calldatas, - newProposal.startBlock, - newProposal.endBlock, newProposal.updatePeriodEndBlock, newProposal.proposalThreshold, minQuorumVotes, - description + clientId ); } function checkPropThreshold( - NounsDAOStorageV3.StorageV3 storage ds, + NounsDAOTypes.Storage storage ds, uint256 votes, uint256 adjustedTotalSupply ) internal view returns (uint256 propThreshold) { @@ -974,9 +979,9 @@ library NounsDAOV3Proposals { } function verifyProposalSignature( - NounsDAOStorageV3.StorageV3 storage ds, + NounsDAOTypes.Storage storage ds, bytes memory proposalEncodeData, - NounsDAOStorageV3.ProposerSignature memory proposerSignature, + NounsDAOTypes.ProposerSignature memory proposerSignature, bytes32 typehash ) internal view { bytes32 sigHash = keccak256(proposerSignature.sig); @@ -1015,4 +1020,8 @@ library NounsDAOV3Proposals { function bps2Uint(uint256 bps, uint256 number) internal pure returns (uint256) { return (number * bps) / 10000; } + + function max(uint256 a, uint256 b) internal pure returns (uint256) { + return a > b ? a : b; + } } diff --git a/packages/nouns-contracts/contracts/governance/NounsDAOProxy.sol b/packages/nouns-contracts/contracts/governance/NounsDAOProxy.sol deleted file mode 100644 index f42e3bf60e..0000000000 --- a/packages/nouns-contracts/contracts/governance/NounsDAOProxy.sol +++ /dev/null @@ -1,141 +0,0 @@ -// SPDX-License-Identifier: BSD-3-Clause - -/// @title The Nouns DAO proxy contract - -/********************************* - * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ * - * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ * - * ░░░░░░█████████░░█████████░░░ * - * ░░░░░░██░░░████░░██░░░████░░░ * - * ░░██████░░░████████░░░████░░░ * - * ░░██░░██░░░████░░██░░░████░░░ * - * ░░██░░██░░░████░░██░░░████░░░ * - * ░░░░░░█████████░░█████████░░░ * - * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ * - * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ * - *********************************/ - -// LICENSE -// NounsDAOProxy.sol is a modified version of Compound Lab's GovernorBravoDelegator.sol: -// https://github.com/compound-finance/compound-protocol/blob/b9b14038612d846b83f8a009a82c38974ff2dcfe/contracts/Governance/GovernorBravoDelegator.sol -// -// GovernorBravoDelegator.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 -// -// -// NounsDAOProxy.sol uses parts of Open Zeppelin's Proxy.sol: -// https://github.com/OpenZeppelin/openzeppelin-contracts/blob/5c8746f56b4bed8cc9e0e044f5f69ab2f9428ce1/contracts/proxy/Proxy.sol -// -// Proxy.sol source code licensed under MIT License. -// -// MODIFICATIONS -// The fallback() and receive() functions of Proxy.sol have been used to allow Solidity > 0.6.0 compatibility - -pragma solidity ^0.8.6; - -import './NounsDAOInterfaces.sol'; - -contract NounsDAOProxy is NounsDAOProxyStorage, NounsDAOEvents { - constructor( - address timelock_, - address nouns_, - address vetoer_, - address admin_, - address implementation_, - uint256 votingPeriod_, - uint256 votingDelay_, - uint256 proposalThresholdBPS_, - uint256 quorumVotesBPS_ - ) { - // Admin set to msg.sender for initialization - admin = msg.sender; - - delegateTo( - implementation_, - abi.encodeWithSignature( - 'initialize(address,address,address,uint256,uint256,uint256,uint256)', - timelock_, - nouns_, - vetoer_, - votingPeriod_, - votingDelay_, - proposalThresholdBPS_, - quorumVotesBPS_ - ) - ); - - _setImplementation(implementation_); - - admin = admin_; - } - - /** - * @notice Called by the admin to update the implementation of the delegator - * @param implementation_ The address of the new implementation for delegation - */ - function _setImplementation(address implementation_) public { - require(msg.sender == admin, 'NounsDAOProxy::_setImplementation: admin only'); - require(implementation_ != address(0), 'NounsDAOProxy::_setImplementation: invalid implementation address'); - - address oldImplementation = implementation; - implementation = implementation_; - - emit NewImplementation(oldImplementation, implementation); - } - - /** - * @notice Internal method to delegate execution to another contract - * @dev It returns to the external caller whatever the implementation returns or forwards reverts - * @param callee The contract to delegatecall - * @param data The raw data to delegatecall - */ - function delegateTo(address callee, bytes memory data) internal { - (bool success, bytes memory returnData) = callee.delegatecall(data); - assembly { - if eq(success, 0) { - revert(add(returnData, 0x20), returndatasize()) - } - } - } - - /** - * @dev Delegates execution to an implementation contract. - * It returns to the external caller whatever the implementation returns - * or forwards reverts. - */ - function _fallback() internal { - // delegate all other functions to current implementation - (bool success, ) = implementation.delegatecall(msg.data); - - assembly { - let free_mem_ptr := mload(0x40) - returndatacopy(free_mem_ptr, 0, returndatasize()) - - switch success - case 0 { - revert(free_mem_ptr, returndatasize()) - } - default { - return(free_mem_ptr, returndatasize()) - } - } - } - - /** - * @dev Fallback function that delegates calls to the `implementation`. Will run if no other - * function in the contract matches the call data. - */ - fallback() external payable { - _fallback(); - } - - /** - * @dev Fallback function that delegates calls to `implementation`. Will run if call data - * is empty. - */ - receive() external payable { - _fallback(); - } -} diff --git a/packages/nouns-contracts/contracts/governance/NounsDAOProxyV2.sol b/packages/nouns-contracts/contracts/governance/NounsDAOProxyV2.sol deleted file mode 100644 index ca05e50616..0000000000 --- a/packages/nouns-contracts/contracts/governance/NounsDAOProxyV2.sol +++ /dev/null @@ -1,144 +0,0 @@ -// SPDX-License-Identifier: BSD-3-Clause - -/// @title The Nouns DAO proxy contract for V2 - -/********************************* - * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ * - * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ * - * ░░░░░░█████████░░█████████░░░ * - * ░░░░░░██░░░████░░██░░░████░░░ * - * ░░██████░░░████████░░░████░░░ * - * ░░██░░██░░░████░░██░░░████░░░ * - * ░░██░░██░░░████░░██░░░████░░░ * - * ░░░░░░█████████░░█████████░░░ * - * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ * - * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ * - *********************************/ - -// NounsDAOProxyV2.sol is a modified version of NounsDAOProxy.sol, tailored for the DAO's V2. -// Its main purpose is to support people wishing to deploy V2 directly, without having to deploy V1 first and then upgrade. - -// LICENSE -// NounsDAOProxy.sol is a modified version of Compound Lab's GovernorBravoDelegator.sol: -// https://github.com/compound-finance/compound-protocol/blob/b9b14038612d846b83f8a009a82c38974ff2dcfe/contracts/Governance/GovernorBravoDelegator.sol -// -// GovernorBravoDelegator.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 -// -// -// NounsDAOProxy.sol uses parts of Open Zeppelin's Proxy.sol: -// https://github.com/OpenZeppelin/openzeppelin-contracts/blob/5c8746f56b4bed8cc9e0e044f5f69ab2f9428ce1/contracts/proxy/Proxy.sol -// -// Proxy.sol source code licensed under MIT License. -// -// MODIFICATIONS -// The fallback() and receive() functions of Proxy.sol have been used to allow Solidity > 0.6.0 compatibility - -pragma solidity ^0.8.6; - -import './NounsDAOInterfaces.sol'; - -contract NounsDAOProxyV2 is NounsDAOStorageV2, NounsDAOEvents { - constructor( - address timelock_, - address nouns_, - address vetoer_, - address admin_, - address implementation_, - uint256 votingPeriod_, - uint256 votingDelay_, - uint256 proposalThresholdBPS_, - DynamicQuorumParams memory dynamicQuorumParams_ - ) { - // Admin set to msg.sender for initialization - admin = msg.sender; - - delegateTo( - implementation_, - abi.encodeWithSignature( - 'initialize(address,address,address,uint256,uint256,uint256,(uint16,uint16,uint32))', - timelock_, - nouns_, - vetoer_, - votingPeriod_, - votingDelay_, - proposalThresholdBPS_, - dynamicQuorumParams_ - ) - ); - - _setImplementation(implementation_); - - admin = admin_; - } - - /** - * @notice Called by the admin to update the implementation of the delegator - * @param implementation_ The address of the new implementation for delegation - */ - function _setImplementation(address implementation_) public { - require(msg.sender == admin, 'NounsDAOProxy::_setImplementation: admin only'); - require(implementation_ != address(0), 'NounsDAOProxy::_setImplementation: invalid implementation address'); - - address oldImplementation = implementation; - implementation = implementation_; - - emit NewImplementation(oldImplementation, implementation); - } - - /** - * @notice Internal method to delegate execution to another contract - * @dev It returns to the external caller whatever the implementation returns or forwards reverts - * @param callee The contract to delegatecall - * @param data The raw data to delegatecall - */ - function delegateTo(address callee, bytes memory data) internal { - (bool success, bytes memory returnData) = callee.delegatecall(data); - assembly { - if eq(success, 0) { - revert(add(returnData, 0x20), returndatasize()) - } - } - } - - /** - * @dev Delegates execution to an implementation contract. - * It returns to the external caller whatever the implementation returns - * or forwards reverts. - */ - function _fallback() internal { - // delegate all other functions to current implementation - (bool success, ) = implementation.delegatecall(msg.data); - - assembly { - let free_mem_ptr := mload(0x40) - returndatacopy(free_mem_ptr, 0, returndatasize()) - - switch success - case 0 { - revert(free_mem_ptr, returndatasize()) - } - default { - return(free_mem_ptr, returndatasize()) - } - } - } - - /** - * @dev Fallback function that delegates calls to the `implementation`. Will run if no other - * function in the contract matches the call data. - */ - fallback() external payable { - _fallback(); - } - - /** - * @dev Fallback function that delegates calls to `implementation`. Will run if call data - * is empty. - */ - receive() external payable { - _fallback(); - } -} diff --git a/packages/nouns-contracts/contracts/governance/NounsDAOProxyV3.sol b/packages/nouns-contracts/contracts/governance/NounsDAOProxyV3.sol index 490c02c100..309e03ec03 100644 --- a/packages/nouns-contracts/contracts/governance/NounsDAOProxyV3.sol +++ b/packages/nouns-contracts/contracts/governance/NounsDAOProxyV3.sol @@ -38,9 +38,21 @@ pragma solidity ^0.8.19; -import './NounsDAOInterfaces.sol'; +import { NounsDAOTypes } from './NounsDAOInterfaces.sol'; + +contract NounsDAOProxyV3 { + /// @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; + + /// @notice Emitted when implementation is changed + event NewImplementation(address oldImplementation, address newImplementation); -contract NounsDAOProxyV3 is NounsDAOProxyStorage, NounsDAOEvents { constructor( address timelock_, address nouns_, @@ -49,8 +61,8 @@ contract NounsDAOProxyV3 is NounsDAOProxyStorage, NounsDAOEvents { address vetoer_, address admin_, address implementation_, - NounsDAOStorageV3.NounsDAOParams memory daoParams_, - NounsDAOStorageV3.DynamicQuorumParams memory dynamicQuorumParams_ + NounsDAOTypes.NounsDAOParams memory daoParams_, + NounsDAOTypes.DynamicQuorumParams memory dynamicQuorumParams_ ) { // Admin set to msg.sender for initialization admin = msg.sender; diff --git a/packages/nouns-contracts/contracts/governance/NounsDAOV3Votes.sol b/packages/nouns-contracts/contracts/governance/NounsDAOVotes.sol similarity index 76% rename from packages/nouns-contracts/contracts/governance/NounsDAOV3Votes.sol rename to packages/nouns-contracts/contracts/governance/NounsDAOVotes.sol index 6ac54dfcc4..78001b86ef 100644 --- a/packages/nouns-contracts/contracts/governance/NounsDAOV3Votes.sol +++ b/packages/nouns-contracts/contracts/governance/NounsDAOVotes.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-3.0 -/// @title Library for NounsDAOLogicV3 contract containing all the voting related code +/// @title Library for Nouns DAO Logic containing all the voting related code /********************************* * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ * @@ -18,11 +18,11 @@ pragma solidity ^0.8.19; import './NounsDAOInterfaces.sol'; -import { NounsDAOV3Proposals } from './NounsDAOV3Proposals.sol'; +import { NounsDAOProposals } from './NounsDAOProposals.sol'; import { SafeCast } from '@openzeppelin/contracts/utils/math/SafeCast.sol'; -library NounsDAOV3Votes { - using NounsDAOV3Proposals for NounsDAOStorageV3.StorageV3; +library NounsDAOVotes { + using NounsDAOProposals for NounsDAOTypes.Storage; error CanOnlyVoteAgainstDuringObjectionPeriod(); @@ -67,12 +67,8 @@ library NounsDAOV3Votes { * @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( - NounsDAOStorageV3.StorageV3 storage ds, - uint256 proposalId, - uint8 support - ) external { - emit VoteCast(msg.sender, proposalId, support, castVoteInternal(ds, msg.sender, proposalId, support), ''); + function castVote(NounsDAOTypes.Storage storage ds, uint256 proposalId, uint8 support) external { + emit VoteCast(msg.sender, proposalId, support, castVoteInternal(ds, msg.sender, proposalId, support, 0), ''); } /** @@ -83,14 +79,16 @@ library NounsDAOV3Votes { * 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 clientId The ID of the client that faciliated posting the vote onchain * @dev Reentrancy is defended against in `castVoteInternal` at the `receipt.hasVoted == false` require statement. */ function castRefundableVote( - NounsDAOStorageV3.StorageV3 storage ds, + NounsDAOTypes.Storage storage ds, uint256 proposalId, - uint8 support + uint8 support, + uint32 clientId ) external { - castRefundableVoteInternal(ds, proposalId, support, ''); + castRefundableVoteInternal(ds, proposalId, support, '', clientId); } /** @@ -105,12 +103,13 @@ library NounsDAOV3Votes { * @dev Reentrancy is defended against in `castVoteInternal` at the `receipt.hasVoted == false` require statement. */ function castRefundableVoteWithReason( - NounsDAOStorageV3.StorageV3 storage ds, + NounsDAOTypes.Storage storage ds, uint256 proposalId, uint8 support, - string calldata reason + string calldata reason, + uint32 clientId ) external { - castRefundableVoteInternal(ds, proposalId, support, reason); + castRefundableVoteInternal(ds, proposalId, support, reason, clientId); } /** @@ -118,17 +117,20 @@ library NounsDAOV3Votes { * @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 + * @param clientId The ID of the client that faciliated posting the vote onchain * @dev Reentrancy is defended against in `castVoteInternal` at the `receipt.hasVoted == false` require statement. */ function castRefundableVoteInternal( - NounsDAOStorageV3.StorageV3 storage ds, + NounsDAOTypes.Storage storage ds, uint256 proposalId, uint8 support, - string memory reason + string memory reason, + uint32 clientId ) internal { uint256 startGas = gasleft(); - uint96 votes = castVoteInternal(ds, msg.sender, proposalId, support); + uint96 votes = castVoteInternal(ds, msg.sender, proposalId, support, clientId); emit VoteCast(msg.sender, proposalId, support, votes, reason); + if (clientId > 0) emit NounsDAOEventsV3.VoteCastWithClientId(msg.sender, proposalId, clientId); if (votes > 0) { _refundGas(startGas); } @@ -141,12 +143,18 @@ library NounsDAOV3Votes { * @param reason The reason given for the vote by the voter */ function castVoteWithReason( - NounsDAOStorageV3.StorageV3 storage ds, + NounsDAOTypes.Storage storage ds, uint256 proposalId, uint8 support, string calldata reason ) external { - emit VoteCast(msg.sender, proposalId, support, castVoteInternal(ds, msg.sender, proposalId, support), reason); + emit VoteCast( + msg.sender, + proposalId, + support, + castVoteInternal(ds, msg.sender, proposalId, support, 0), + reason + ); } /** @@ -154,7 +162,7 @@ library NounsDAOV3Votes { * @dev External function that accepts EIP-712 signatures for voting on proposals. */ function castVoteBySig( - NounsDAOStorageV3.StorageV3 storage ds, + NounsDAOTypes.Storage storage ds, uint256 proposalId, uint8 support, uint8 v, @@ -168,7 +176,7 @@ library NounsDAOV3Votes { 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(ds, signatory, proposalId, support), ''); + emit VoteCast(signatory, proposalId, support, castVoteInternal(ds, signatory, proposalId, support, 0), ''); } /** @@ -179,24 +187,32 @@ library NounsDAOV3Votes { * @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 + * @param clientId The ID of the client that faciliated posting the vote onchain + * @return votes The number of votes cast */ function castVoteInternal( - NounsDAOStorageV3.StorageV3 storage ds, + NounsDAOTypes.Storage storage ds, address voter, uint256 proposalId, - uint8 support - ) internal returns (uint96) { - NounsDAOStorageV3.ProposalState proposalState = ds.stateInternal(proposalId); + uint8 support, + uint32 clientId + ) internal returns (uint96 votes) { + NounsDAOTypes.ProposalState proposalState = ds.stateInternal(proposalId); - if (proposalState == NounsDAOStorageV3.ProposalState.Active) { - return castVoteDuringVotingPeriodInternal(ds, proposalId, voter, support); - } else if (proposalState == NounsDAOStorageV3.ProposalState.ObjectionPeriod) { + if (proposalState == NounsDAOTypes.ProposalState.Active) { + votes = castVoteDuringVotingPeriodInternal(ds, proposalId, voter, support); + } else if (proposalState == NounsDAOTypes.ProposalState.ObjectionPeriod) { if (support != 0) revert CanOnlyVoteAgainstDuringObjectionPeriod(); - return castObjectionInternal(ds, proposalId, voter); + votes = castObjectionInternal(ds, proposalId, voter); + } else { + revert('NounsDAO::castVoteInternal: voting is closed'); } - revert('NounsDAO::castVoteInternal: voting is closed'); + NounsDAOTypes.ClientVoteData memory voteData = ds._proposals[proposalId].voteClients[clientId]; + ds._proposals[proposalId].voteClients[clientId] = NounsDAOTypes.ClientVoteData({ + votes: uint32(voteData.votes + votes), + txs: voteData.txs + 1 + }); } /** @@ -208,18 +224,17 @@ library NounsDAOV3Votes { * @return The number of votes cast */ function castVoteDuringVotingPeriodInternal( - NounsDAOStorageV3.StorageV3 storage ds, + NounsDAOTypes.Storage storage ds, uint256 proposalId, address voter, uint8 support ) internal returns (uint96) { require(support <= 2, 'NounsDAO::castVoteDuringVotingPeriodInternal: invalid vote type'); - NounsDAOStorageV3.Proposal storage proposal = ds._proposals[proposalId]; - NounsDAOStorageV3.Receipt storage receipt = proposal.receipts[voter]; + NounsDAOTypes.Proposal storage proposal = ds._proposals[proposalId]; + NounsDAOTypes.Receipt storage receipt = proposal.receipts[voter]; require(receipt.hasVoted == false, 'NounsDAO::castVoteDuringVotingPeriodInternal: 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 = ds.nouns.getPriorVotes(voter, proposalVoteSnapshotBlock(ds, proposalId, proposal)); + uint96 votes = ds.nouns.getPriorVotes(voter, proposal.startBlock); bool isForVoteInLastMinuteWindow = false; if (support == 1) { @@ -273,18 +288,15 @@ library NounsDAOV3Votes { * @return The number of votes cast */ function castObjectionInternal( - NounsDAOStorageV3.StorageV3 storage ds, + NounsDAOTypes.Storage storage ds, uint256 proposalId, address voter ) internal returns (uint96) { - NounsDAOStorageV3.Proposal storage proposal = ds._proposals[proposalId]; - NounsDAOStorageV3.Receipt storage receipt = proposal.receipts[voter]; + NounsDAOTypes.Proposal storage proposal = ds._proposals[proposalId]; + NounsDAOTypes.Receipt storage receipt = proposal.receipts[voter]; require(receipt.hasVoted == false, 'NounsDAO::castVoteInternal: voter already voted'); - uint96 votes = receipt.votes = ds.nouns.getPriorVotes( - voter, - proposalVoteSnapshotBlock(ds, proposalId, proposal) - ); + uint96 votes = receipt.votes = ds.nouns.getPriorVotes(voter, proposal.startBlock); receipt.hasVoted = true; receipt.support = 0; proposal.againstVotes = proposal.againstVotes + votes; @@ -307,28 +319,6 @@ library NounsDAOV3Votes { } } - /** - * @notice Internal function that returns the snapshot block number to use given a proposalId. The choice is - * between the proposal's creation block and the proposal's voting start block, to allow a smooth migration from - * creation block to start block. - * @param proposalId The id of the proposal being voted on - * @param proposal The proposal storage reference, used to read `creationBlock` and `startBlock` - */ - function proposalVoteSnapshotBlock( - NounsDAOStorageV3.StorageV3 storage ds, - uint256 proposalId, - NounsDAOStorageV3.Proposal storage proposal - ) internal view returns (uint256) { - // The idea is to temporarily use this code that would still use `creationBlock` until all proposals are using - // `startBlock`, then we can deploy a quick DAO fix that removes this line and only uses `startBlock`. - // In that version upgrade we can also zero-out and remove this storage variable for max cleanup. - uint256 voteSnapshotBlockSwitchProposalId = ds.voteSnapshotBlockSwitchProposalId; - if (proposalId < voteSnapshotBlockSwitchProposalId || voteSnapshotBlockSwitchProposalId == 0) { - return proposal.creationBlock; - } - return proposal.startBlock; - } - function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } diff --git a/packages/nouns-contracts/contracts/governance/data/NounsDAOData.sol b/packages/nouns-contracts/contracts/governance/data/NounsDAOData.sol index 64528fc3e4..86a08d86ef 100644 --- a/packages/nouns-contracts/contracts/governance/data/NounsDAOData.sol +++ b/packages/nouns-contracts/contracts/governance/data/NounsDAOData.sol @@ -18,12 +18,16 @@ pragma solidity ^0.8.19; import { OwnableUpgradeable } from '@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol'; -import { NounsDAOV3Proposals } from '../NounsDAOV3Proposals.sol'; -import { NounsTokenLike } from '../NounsDAOInterfaces.sol'; +import { NounsDAOProposals } from '../NounsDAOProposals.sol'; +import { NounsTokenLike, NounsDAOTypes } from '../NounsDAOInterfaces.sol'; import { SignatureChecker } from '../../external/openzeppelin/SignatureChecker.sol'; import { UUPSUpgradeable } from '@openzeppelin/contracts/proxy/utils/UUPSUpgradeable.sol'; import { NounsDAODataEvents } from './NounsDAODataEvents.sol'; +interface INounsDAO { + function proposalsV3(uint256 proposalId) external view returns (NounsDAOTypes.ProposalCondensedV3 memory); +} + contract NounsDAOData is OwnableUpgradeable, UUPSUpgradeable, NounsDAODataEvents { /** * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ @@ -38,6 +42,9 @@ contract NounsDAOData is OwnableUpgradeable, UUPSUpgradeable, NounsDAODataEvents error FailedWithdrawingETH(bytes data); error InvalidSignature(); error InvalidSupportValue(); + error ProposalToUpdateMustBeUpdatable(); + error OnlyProposerCanCreateUpdateCandidate(); + error UpdateProposalCandidatesOnlyWorkWithProposalsBySigs(); /** * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ @@ -99,6 +106,12 @@ contract NounsDAOData is OwnableUpgradeable, UUPSUpgradeable, NounsDAODataEvents /** * @notice Create a new proposal candidate by emitting an event. Nouners can post for free, while non-Nouners must pay `createCandidateCost` in ETH. + * When used to update a proposal created by signatures, `proposalIdToUpdate` should be the ID of the proposal to update, + * and no fee is required. + * Also in this case, the following conditions must be met: + * 1. The proposal must be in the Updatable state. + * 2. `msg.sender` must be the same as the proposer of the proposal to update. + * 3. The proposal must have at least one signer. * @dev Reverts if the proposer (msg.sender) has already created a candidate with the same slug. * @param targets the candidate proposal targets. * @param values the candidate proposal values. @@ -117,14 +130,25 @@ contract NounsDAOData is OwnableUpgradeable, UUPSUpgradeable, NounsDAODataEvents string memory slug, uint256 proposalIdToUpdate ) external payable { - if (!isNouner(msg.sender) && msg.value < createCandidateCost) revert MustBeNounerOrPaySufficientFee(); + if (proposalIdToUpdate > 0) { + INounsDAO dao = INounsDAO(nounsDao); + NounsDAOTypes.ProposalCondensedV3 memory propInfo = dao.proposalsV3(proposalIdToUpdate); + + if (block.number > propInfo.updatePeriodEndBlock) revert ProposalToUpdateMustBeUpdatable(); + if (propInfo.proposer != msg.sender) revert OnlyProposerCanCreateUpdateCandidate(); + if (propInfo.signers.length == 0) revert UpdateProposalCandidatesOnlyWorkWithProposalsBySigs(); + } else { + if (!isNouner(msg.sender) && msg.value < createCandidateCost) revert MustBeNounerOrPaySufficientFee(); + } + if (propCandidates[msg.sender][keccak256(bytes(slug))]) revert SlugAlreadyUsed(); + NounsDAOProposals.checkProposalTxs(NounsDAOProposals.ProposalTxs(targets, values, signatures, calldatas)); propCandidates[msg.sender][keccak256(bytes(slug))] = true; - bytes memory encodedProp = NounsDAOV3Proposals.calcProposalEncodeData( + bytes memory encodedProp = NounsDAOProposals.calcProposalEncodeData( msg.sender, - NounsDAOV3Proposals.ProposalTxs(targets, values, signatures, calldatas), + NounsDAOProposals.ProposalTxs(targets, values, signatures, calldatas), description ); if (proposalIdToUpdate > 0) { @@ -170,10 +194,11 @@ contract NounsDAOData is OwnableUpgradeable, UUPSUpgradeable, NounsDAODataEvents ) external payable { if (!isNouner(msg.sender) && msg.value < updateCandidateCost) revert MustBeNounerOrPaySufficientFee(); if (!propCandidates[msg.sender][keccak256(bytes(slug))]) revert SlugDoesNotExist(); + NounsDAOProposals.checkProposalTxs(NounsDAOProposals.ProposalTxs(targets, values, signatures, calldatas)); - bytes memory encodedProp = NounsDAOV3Proposals.calcProposalEncodeData( + bytes memory encodedProp = NounsDAOProposals.calcProposalEncodeData( msg.sender, - NounsDAOV3Proposals.ProposalTxs(targets, values, signatures, calldatas), + NounsDAOProposals.ProposalTxs(targets, values, signatures, calldatas), description ); if (proposalIdToUpdate > 0) { @@ -216,7 +241,7 @@ contract NounsDAOData is OwnableUpgradeable, UUPSUpgradeable, NounsDAODataEvents * @param slug the slug of the proposal candidate signer signed on. * @param proposalIdToUpdate if this is an update to an existing proposal, the ID of the proposal to update, otherwise 0. * @param encodedProp the abi encoding of the candidate version signed; should be identical to the output of - * the `NounsDAOV3Proposals.calcProposalEncodeData` function. + * the `NounsDAOProposals.calcProposalEncodeData` function. * @param reason signer's reason free text. */ function addSignature( @@ -231,10 +256,10 @@ contract NounsDAOData is OwnableUpgradeable, UUPSUpgradeable, NounsDAODataEvents if (!propCandidates[proposer][keccak256(bytes(slug))]) revert SlugDoesNotExist(); bytes32 typeHash = proposalIdToUpdate == 0 - ? NounsDAOV3Proposals.PROPOSAL_TYPEHASH - : NounsDAOV3Proposals.UPDATE_PROPOSAL_TYPEHASH; + ? NounsDAOProposals.PROPOSAL_TYPEHASH + : NounsDAOProposals.UPDATE_PROPOSAL_TYPEHASH; - bytes32 sigDigest = NounsDAOV3Proposals.sigDigest(typeHash, encodedProp, expirationTimestamp, nounsDao); + bytes32 sigDigest = NounsDAOProposals.sigDigest(typeHash, encodedProp, expirationTimestamp, nounsDao); if (!SignatureChecker.isValidSignatureNow(msg.sender, sigDigest, sig)) revert InvalidSignature(); @@ -258,11 +283,7 @@ contract NounsDAOData is OwnableUpgradeable, UUPSUpgradeable, NounsDAODataEvents * @param support msg.sender's vote-like feedback: 0 is against, 1 is for, 2 is abstain. * @param reason their free text feedback. */ - function sendFeedback( - uint256 proposalId, - uint8 support, - string memory reason - ) external { + function sendFeedback(uint256 proposalId, uint8 support, string memory reason) external { if (support > 2) revert InvalidSupportValue(); emit FeedbackSent(msg.sender, proposalId, support, reason); @@ -276,12 +297,7 @@ contract NounsDAOData is OwnableUpgradeable, UUPSUpgradeable, NounsDAODataEvents * @param support msg.sender's vote-like feedback: 0 is against, 1 is for, 2 is abstain. * @param reason their free text feedback. */ - function sendCandidateFeedback( - address proposer, - string memory slug, - uint8 support, - string memory reason - ) external { + function sendCandidateFeedback(address proposer, string memory slug, uint8 support, string memory reason) external { if (!propCandidates[proposer][keccak256(bytes(slug))]) revert SlugDoesNotExist(); if (support > 2) revert InvalidSupportValue(); diff --git a/packages/nouns-contracts/contracts/governance/fork/ForkDAODeployer.sol b/packages/nouns-contracts/contracts/governance/fork/ForkDAODeployer.sol index d455248eef..25ca4c1fcb 100644 --- a/packages/nouns-contracts/contracts/governance/fork/ForkDAODeployer.sol +++ b/packages/nouns-contracts/contracts/governance/fork/ForkDAODeployer.sol @@ -18,16 +18,18 @@ pragma solidity ^0.8.19; import { ERC1967Proxy } from '@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol'; -import { IForkDAODeployer, INounsDAOForkEscrow, NounsDAOStorageV3 } from '../NounsDAOInterfaces.sol'; +import { IForkDAODeployer, INounsDAOForkEscrow, NounsDAOTypes } from '../NounsDAOInterfaces.sol'; import { NounsTokenFork } from './newdao/token/NounsTokenFork.sol'; import { NounsAuctionHouseFork } from './newdao/NounsAuctionHouseFork.sol'; import { NounsDAOExecutorV2 } from '../NounsDAOExecutorV2.sol'; -import { NounsDAOProxy } from '../NounsDAOProxy.sol'; -import { NounsDAOLogicV3 } from '../NounsDAOLogicV3.sol'; import { NounsDAOLogicV1Fork } from './newdao/governance/NounsDAOLogicV1Fork.sol'; import { NounsToken } from '../../NounsToken.sol'; import { NounsAuctionHouse } from '../../NounsAuctionHouse.sol'; +interface INounsDAOForkTokens { + function erc20TokensToIncludeInFork() external view returns (address[] memory); +} + contract ForkDAODeployer is IForkDAODeployer { event DAODeployed(address token, address auction, address governor, address treasury); @@ -89,10 +91,10 @@ contract ForkDAODeployer is IForkDAODeployer { * @return treasury The address of the fork DAO treasury * @return token The address of the fork DAO token */ - function deployForkDAO(uint256 forkingPeriodEndTimestamp, INounsDAOForkEscrow forkEscrow) - external - returns (address treasury, address token) - { + function deployForkDAO( + uint256 forkingPeriodEndTimestamp, + INounsDAOForkEscrow forkEscrow + ) external returns (address treasury, address token) { token = address(new ERC1967Proxy(tokenImpl, '')); address auction = address(new ERC1967Proxy(auctionImpl, '')); address governor = address(new ERC1967Proxy(governorImpl, '')); @@ -131,13 +133,8 @@ contract ForkDAODeployer is IForkDAODeployer { /** * @dev Used to prevent the 'Stack too deep' error in the main deploy function. */ - function initDAO( - address governor, - address treasury, - address token, - NounsDAOExecutorV2 originalTimelock - ) internal { - NounsDAOLogicV3 originalDAO = NounsDAOLogicV3(payable(originalTimelock.admin())); + function initDAO(address governor, address treasury, address token, NounsDAOExecutorV2 originalTimelock) internal { + INounsDAOForkTokens originalDAO = INounsDAOForkTokens(payable(originalTimelock.admin())); NounsDAOLogicV1Fork(governor).initialize( treasury, token, diff --git a/packages/nouns-contracts/contracts/governance/fork/NounsDAOV3Fork.sol b/packages/nouns-contracts/contracts/governance/fork/NounsDAOFork.sol similarity index 88% rename from packages/nouns-contracts/contracts/governance/fork/NounsDAOV3Fork.sol rename to packages/nouns-contracts/contracts/governance/fork/NounsDAOFork.sol index d87ffc701a..267fd87a4e 100644 --- a/packages/nouns-contracts/contracts/governance/fork/NounsDAOV3Fork.sol +++ b/packages/nouns-contracts/contracts/governance/fork/NounsDAOFork.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-3.0 -/// @title Library for NounsDAOLogicV3 contract containing the dao fork logic +/// @title Library for Nouns DAO Logic containing the dao fork logic /********************************* * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ * @@ -17,11 +17,11 @@ pragma solidity ^0.8.19; -import { NounsDAOStorageV3, INounsDAOForkEscrow, INounsDAOExecutorV2 } from '../NounsDAOInterfaces.sol'; +import { NounsDAOTypes, INounsDAOForkEscrow, INounsDAOExecutorV2 } from '../NounsDAOInterfaces.sol'; import { IERC20 } from '@openzeppelin/contracts/token/ERC20/IERC20.sol'; import { NounsTokenFork } from './newdao/token/NounsTokenFork.sol'; -library NounsDAOV3Fork { +library NounsDAOFork { error ForkThresholdNotMet(); error ForkPeriodNotActive(); error ForkPeriodActive(); @@ -72,7 +72,7 @@ library NounsDAOV3Fork { * @param reason the reason for want to fork. This will only be used to emit event. */ function escrowToFork( - NounsDAOStorageV3.StorageV3 storage ds, + NounsDAOTypes.Storage storage ds, uint256[] calldata tokenIds, uint256[] calldata proposalIds, string calldata reason @@ -92,7 +92,7 @@ library NounsDAOV3Fork { * Only allowed to withdraw tokens that the sender has escrowed. * @param tokenIds the tokenIds to withdraw */ - function withdrawFromForkEscrow(NounsDAOStorageV3.StorageV3 storage ds, uint256[] calldata tokenIds) external { + function withdrawFromForkEscrow(NounsDAOTypes.Storage storage ds, uint256[] calldata tokenIds) external { if (isForkPeriodActive(ds)) revert ForkPeriodActive(); INounsDAOForkEscrow forkEscrow = ds.forkEscrow; @@ -108,10 +108,7 @@ library NounsDAOV3Fork { * @return forkTreasury The address of the new DAO's treasury * @return forkToken The address of the new DAO's token */ - function executeFork(NounsDAOStorageV3.StorageV3 storage ds) - external - returns (address forkTreasury, address forkToken) - { + function executeFork(NounsDAOTypes.Storage storage ds) external returns (address forkTreasury, address forkToken) { if (isForkPeriodActive(ds)) revert ForkPeriodActive(); INounsDAOForkEscrow forkEscrow = ds.forkEscrow; @@ -139,7 +136,7 @@ library NounsDAOV3Fork { * @param tokenIds the tokenIds to send to the DAO in exchange for joining the fork */ function joinFork( - NounsDAOStorageV3.StorageV3 storage ds, + NounsDAOTypes.Storage storage ds, uint256[] calldata tokenIds, uint256[] calldata proposalIds, string calldata reason @@ -164,9 +161,10 @@ library NounsDAOV3Fork { * @dev Only the DAO can call this function * @param tokenIds the tokenIds to withdraw */ - function withdrawDAONounsFromEscrowToTreasury(NounsDAOStorageV3.StorageV3 storage ds, uint256[] calldata tokenIds) - external - { + function withdrawDAONounsFromEscrowToTreasury( + NounsDAOTypes.Storage storage ds, + uint256[] calldata tokenIds + ) external { withdrawDAONounsFromEscrow(ds, tokenIds, address(ds.timelock)); } @@ -177,7 +175,7 @@ library NounsDAOV3Fork { * @param to the address to send the nouns to */ function withdrawDAONounsFromEscrowIncreasingTotalSupply( - NounsDAOStorageV3.StorageV3 storage ds, + NounsDAOTypes.Storage storage ds, uint256[] calldata tokenIds, address to ) external { @@ -189,7 +187,7 @@ library NounsDAOV3Fork { } function withdrawDAONounsFromEscrow( - NounsDAOStorageV3.StorageV3 storage ds, + NounsDAOTypes.Storage storage ds, uint256[] calldata tokenIds, address to ) private { @@ -205,14 +203,14 @@ library NounsDAOV3Fork { /** * @notice Returns the required number of tokens to escrow to trigger a fork */ - function forkThreshold(NounsDAOStorageV3.StorageV3 storage ds) public view returns (uint256) { + function forkThreshold(NounsDAOTypes.Storage storage ds) public view returns (uint256) { return (adjustedTotalSupply(ds) * ds.forkThresholdBPS) / 10_000; } /** * @notice Returns the number of tokens currently in escrow, contributing to the fork threshold */ - function numTokensInForkEscrow(NounsDAOStorageV3.StorageV3 storage ds) public view returns (uint256) { + function numTokensInForkEscrow(NounsDAOTypes.Storage storage ds) public view returns (uint256) { return ds.forkEscrow.numTokensInEscrow(); } @@ -221,14 +219,14 @@ library NounsDAOV3Fork { * escrow after it has closed. * This is used when calculating proposal threshold, quorum, fork threshold & treasury split. */ - function adjustedTotalSupply(NounsDAOStorageV3.StorageV3 storage ds) internal view returns (uint256) { + function adjustedTotalSupply(NounsDAOTypes.Storage storage ds) internal view returns (uint256) { return ds.nouns.totalSupply() - ds.nouns.balanceOf(address(ds.timelock)) - ds.forkEscrow.numTokensOwnedByDAO(); } /** * @notice Returns true if noun holders can currently join a fork */ - function isForkPeriodActive(NounsDAOStorageV3.StorageV3 storage ds) internal view returns (bool) { + function isForkPeriodActive(NounsDAOTypes.Storage storage ds) internal view returns (bool) { return ds.forkEndTimestamp > block.timestamp; } @@ -238,7 +236,7 @@ library NounsDAOV3Fork { * Sends ETH and ERC20 tokens listed in `ds.erc20TokensToIncludeInFork`. */ function sendProRataTreasury( - NounsDAOStorageV3.StorageV3 storage ds, + NounsDAOTypes.Storage storage ds, address newDAOTreasury, uint256 tokenCount, uint256 totalSupply diff --git a/packages/nouns-contracts/contracts/governance/fork/newdao/governance/NounsDAOStorageV1Fork.sol b/packages/nouns-contracts/contracts/governance/fork/newdao/governance/NounsDAOStorageV1Fork.sol index 8d18f51046..555fe0508f 100644 --- a/packages/nouns-contracts/contracts/governance/fork/newdao/governance/NounsDAOStorageV1Fork.sol +++ b/packages/nouns-contracts/contracts/governance/fork/newdao/governance/NounsDAOStorageV1Fork.sol @@ -46,7 +46,7 @@ contract NounsDAOStorageV1Fork { INounsTokenForkLike public nouns; /// @notice The official record of all proposals ever proposed - mapping(uint256 => Proposal) public _proposals; + mapping(uint256 => Proposal) internal _proposals; /// @notice The latest proposal for each proposer mapping(address => uint256) public latestProposalIds; diff --git a/packages/nouns-contracts/contracts/interfaces/INounsAuctionHouse.sol b/packages/nouns-contracts/contracts/interfaces/INounsAuctionHouse.sol index 33d37c9254..a926cff8b8 100644 --- a/packages/nouns-contracts/contracts/interfaces/INounsAuctionHouse.sol +++ b/packages/nouns-contracts/contracts/interfaces/INounsAuctionHouse.sol @@ -62,4 +62,16 @@ interface INounsAuctionHouse { function setReservePrice(uint256 reservePrice) external; function setMinBidIncrementPercentage(uint8 minBidIncrementPercentage) external; + + function auction() + external + view + returns ( + uint256, + uint256, + uint256, + uint256, + address payable, + bool + ); } diff --git a/packages/nouns-contracts/contracts/interfaces/INounsAuctionHouseV2.sol b/packages/nouns-contracts/contracts/interfaces/INounsAuctionHouseV2.sol new file mode 100644 index 0000000000..fbba25ade6 --- /dev/null +++ b/packages/nouns-contracts/contracts/interfaces/INounsAuctionHouseV2.sol @@ -0,0 +1,154 @@ +// SPDX-License-Identifier: GPL-3.0 + +/// @title Interface for Noun Auction Houses V2 + +/********************************* + * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ * + * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ * + * ░░░░░░█████████░░█████████░░░ * + * ░░░░░░██░░░████░░██░░░████░░░ * + * ░░██████░░░████████░░░████░░░ * + * ░░██░░██░░░████░░██░░░████░░░ * + * ░░██░░██░░░████░░██░░░████░░░ * + * ░░░░░░█████████░░█████████░░░ * + * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ * + * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ * + *********************************/ + +pragma solidity ^0.8.19; + +interface INounsAuctionHouseV2 { + struct AuctionV2 { + // ID for the Noun (ERC721 token ID) + uint96 nounId; + // ID of the client that facilitated the latest bid, used for client rewards + uint32 clientId; + // The current highest bid amount + uint128 amount; + // The time that the auction started + uint40 startTime; + // The time that the auction is scheduled to end + uint40 endTime; + // The address of the current highest bid + address payable bidder; + // Whether or not the auction has been settled + bool settled; + } + + /// @dev We use this struct as the return value of the `auction` function, to maintain backwards compatibility. + struct AuctionV2View { + // ID for the Noun (ERC721 token ID) + uint96 nounId; + // The current highest bid amount + uint128 amount; + // The time that the auction started + uint40 startTime; + // The time that the auction is scheduled to end + uint40 endTime; + // The address of the current highest bid + address payable bidder; + // Whether or not the auction has been settled + bool settled; + } + + struct SettlementState { + // The block.timestamp when the auction was settled. + uint32 blockTimestamp; + // The winning bid amount, with 10 decimal places (reducing accuracy to save bits). + uint64 amount; + // The address of the auction winner. + address winner; + // ID of the client that facilitated the winning bid, used for client rewards. + uint32 clientId; + // Used only to warm up the storage slot for clientId without setting the clientId value. + bool slotWarmedUp; + } + + struct Settlement { + // The block.timestamp when the auction was settled. + uint32 blockTimestamp; + // The winning bid amount, converted from 10 decimal places to 18, for better client UX. + uint256 amount; + // The address of the auction winner. + address winner; + // ID for the Noun (ERC721 token ID). + uint256 nounId; + // ID of the client that facilitated the winning bid, used for client rewards + uint32 clientId; + } + + /// @dev Using this struct when setting historic prices, and excluding clientId to save gas. + struct SettlementNoClientId { + // The block.timestamp when the auction was settled. + uint32 blockTimestamp; + // The winning bid amount, converted from 10 decimal places to 18, for better client UX. + uint256 amount; + // The address of the auction winner. + address winner; + // ID for the Noun (ERC721 token ID). + uint256 nounId; + } + + event AuctionCreated(uint256 indexed nounId, uint256 startTime, uint256 endTime); + + event AuctionBid(uint256 indexed nounId, address sender, uint256 value, bool extended); + + event AuctionBidWithClientId(uint256 indexed nounId, uint256 value, uint32 indexed clientId); + + event AuctionExtended(uint256 indexed nounId, uint256 endTime); + + event AuctionSettled(uint256 indexed nounId, address winner, uint256 amount); + + event AuctionSettledWithClientId(uint256 indexed nounId, uint32 indexed clientId); + + event AuctionTimeBufferUpdated(uint256 timeBuffer); + + event AuctionReservePriceUpdated(uint256 reservePrice); + + event AuctionMinBidIncrementPercentageUpdated(uint256 minBidIncrementPercentage); + + function settleAuction() external; + + function settleCurrentAndCreateNewAuction() external; + + function createBid(uint256 nounId) external payable; + + function createBid(uint256 nounId, uint32 clientId) external payable; + + function pause() external; + + function unpause() external; + + function setTimeBuffer(uint56 timeBuffer) external; + + function setReservePrice(uint192 reservePrice) external; + + function setMinBidIncrementPercentage(uint8 minBidIncrementPercentage) external; + + function auction() external view returns (AuctionV2View memory); + + function getSettlements( + uint256 auctionCount, + bool skipEmptyValues + ) external view returns (Settlement[] memory settlements); + + function getPrices(uint256 auctionCount) external view returns (uint256[] memory prices); + + function getSettlements( + uint256 startId, + uint256 endId, + bool skipEmptyValues + ) external view returns (Settlement[] memory settlements); + + function getSettlementsFromIdtoTimestamp( + uint256 startId, + uint256 endTimestamp, + bool skipEmptyValues + ) external view returns (Settlement[] memory settlements); + + function warmUpSettlementState(uint256 startId, uint256 endId) external; + + function duration() external view returns (uint256); + + function biddingClient(uint256 nounId) external view returns (uint32 clientId); +} diff --git a/packages/nouns-contracts/contracts/interfaces/INounsDAOLogic.sol b/packages/nouns-contracts/contracts/interfaces/INounsDAOLogic.sol new file mode 100644 index 0000000000..6607920471 --- /dev/null +++ b/packages/nouns-contracts/contracts/interfaces/INounsDAOLogic.sol @@ -0,0 +1,705 @@ +// SPDX-License-Identifier: GPL-3.0 + +/// @title Interface for Noun Auction Houses + +/********************************* + * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ * + * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ * + * ░░░░░░█████████░░█████████░░░ * + * ░░░░░░██░░░████░░██░░░████░░░ * + * ░░██████░░░████████░░░████░░░ * + * ░░██░░██░░░████░░██░░░████░░░ * + * ░░██░░██░░░████░░██░░░████░░░ * + * ░░░░░░█████████░░█████████░░░ * + * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ * + * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ * + *********************************/ + +pragma solidity ^0.8.6; + +import '../governance/NounsDAOInterfaces.sol'; + +interface INounsDAOLogic { + /** + * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + * PROPOSALS + * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + */ + /** + * @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 uint256 Proposal id of new proposal + */ + function propose( + address[] memory targets, + uint256[] memory values, + string[] memory signatures, + bytes[] memory calldatas, + string memory description + ) external returns (uint256); + + function propose( + address[] memory targets, + uint256[] memory values, + string[] memory signatures, + bytes[] memory calldatas, + string memory description, + uint32 clientId + ) external returns (uint256); + + /** + * @notice Function used to propose a new proposal. Sender must have delegates above the proposal threshold. + * This proposal would be executed via the timelockV1 contract. This is meant to be used in case timelockV1 + * is still holding funds or has special permissions to execute on certain contracts. + * @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 uint256 Proposal id of new proposal + */ + function proposeOnTimelockV1( + address[] memory targets, + uint256[] memory values, + string[] memory signatures, + bytes[] memory calldatas, + string memory description + ) external returns (uint256); + + function proposeBySigs( + NounsDAOTypes.ProposerSignature[] memory proposerSignatures, + address[] memory targets, + uint256[] memory values, + string[] memory signatures, + bytes[] memory calldatas, + string memory description, + uint32 clientId + ) external returns (uint256); + + /** + * @notice Function used to propose a new proposal. Sender and signers must have delegates above the proposal threshold + * Signers are regarded as co-proposers, and therefore have the ability to cancel the proposal at any time. + * @param proposerSignatures Array of signers who have signed the proposal and their signatures. + * @dev The signatures follow EIP-712. See `PROPOSAL_TYPEHASH` in NounsDAOProposals.sol + * @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 uint256 Proposal id of new proposal + */ + function proposeBySigs( + NounsDAOTypes.ProposerSignature[] memory proposerSignatures, + address[] memory targets, + uint256[] memory values, + string[] memory signatures, + bytes[] memory calldatas, + string memory description + ) external returns (uint256); + + /** + * @notice Invalidates a signature that may be used for signing a new proposal. + * Once a signature is canceled, the sender can no longer use it again. + * If the sender changes their mind and want to sign the proposal, they can change the expiry timestamp + * in order to produce a new signature. + * The signature will only be invalidated when used by the sender. If used by a different account, it will + * not be invalidated. + * Cancelling a signature for an existing proposal will have no effect. Signers have the ability to cancel + * a proposal they signed if necessary. + * @param sig The signature to cancel + */ + function cancelSig(bytes calldata sig) external; + + /** + * @notice Update a proposal transactions and description. + * Only the proposer can update it, and only during the updateable period. + * @param proposalId Proposal's id + * @param targets Updated target addresses for proposal calls + * @param values Updated eth values for proposal calls + * @param signatures Updated function signatures for proposal calls + * @param calldatas Updated calldatas for proposal calls + * @param description Updated description of the proposal + * @param updateMessage Short message to explain the update + */ + function updateProposal( + uint256 proposalId, + address[] memory targets, + uint256[] memory values, + string[] memory signatures, + bytes[] memory calldatas, + string memory description, + string memory updateMessage + ) external; + + /** + * @notice Updates the proposal's description. Only the proposer can update it, and only during the updateable period. + * @param proposalId Proposal's id + * @param description Updated description of the proposal + * @param updateMessage Short message to explain the update + */ + function updateProposalDescription( + uint256 proposalId, + string calldata description, + string calldata updateMessage + ) external; + + /** + * @notice Updates the proposal's transactions. Only the proposer can update it, and only during the updateable period. + * @param proposalId Proposal's id + * @param targets Updated target addresses for proposal calls + * @param values Updated eth values for proposal calls + * @param signatures Updated function signatures for proposal calls + * @param calldatas Updated calldatas for proposal calls + * @param updateMessage Short message to explain the update + */ + function updateProposalTransactions( + uint256 proposalId, + address[] memory targets, + uint256[] memory values, + string[] memory signatures, + bytes[] memory calldatas, + string memory updateMessage + ) external; + + /** + * @notice Update a proposal's transactions and description that was created with proposeBySigs. + * Only the proposer can update it, during the updateable period. + * Requires the original signers to sign the update. + * @param proposalId Proposal's id + * @param proposerSignatures Array of signers who have signed the proposal and their signatures. + * @dev The signatures follow EIP-712. See `UPDATE_PROPOSAL_TYPEHASH` in NounsDAOProposals.sol + * @param targets Updated target addresses for proposal calls + * @param values Updated eth values for proposal calls + * @param signatures Updated function signatures for proposal calls + * @param calldatas Updated calldatas for proposal calls + * @param description Updated description of the proposal + * @param updateMessage Short message to explain the update + */ + function updateProposalBySigs( + uint256 proposalId, + NounsDAOTypes.ProposerSignature[] memory proposerSignatures, + address[] memory targets, + uint256[] memory values, + string[] memory signatures, + bytes[] memory calldatas, + string memory description, + string memory updateMessage + ) external; + + /** + * @notice Queues a proposal of state succeeded + * @param proposalId The id of the proposal to queue + */ + function queue(uint256 proposalId) external; + + /** + * @notice Executes a queued proposal if eta has passed + * @param proposalId The id of the proposal to execute + */ + function execute(uint256 proposalId) external; + + /** + * @notice Cancels a proposal only if sender is the proposer or a signer, or proposer & signers voting power + * dropped below proposal threshold + * @param proposalId The id of the proposal to cancel + */ + function cancel(uint256 proposalId) external; + + /** + * @notice Gets the state of a proposal + * @param proposalId The id of the proposal + * @return Proposal state + */ + function state(uint256 proposalId) external view returns (NounsDAOTypes.ProposalState); + + /** + * @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 + ); + + /** + * @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 (NounsDAOTypes.Receipt memory); + + /** + * @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, backwards compatible with V1 and V2 + */ + function proposals(uint256 proposalId) external view returns (NounsDAOTypes.ProposalCondensedV2 memory); + + /** + * @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, not backwards compatible as it contains additional values + * like `objectionPeriodEndBlock` and `signers` + */ + function proposalsV3(uint256 proposalId) external view returns (NounsDAOTypes.ProposalCondensedV3 memory); + + function proposalDataForRewards( + uint256 firstProposalId, + uint256 lastProposalId, + uint16 proposalEligibilityQuorumBps, + bool excludeCanceled, + bool requireVotingEnded, + uint32[] calldata votingClientIds + ) external view returns (NounsDAOTypes.ProposalForRewards[] memory); + + /** + * @notice Current proposal threshold using Noun Total Supply + * Differs from `GovernerBravo` which uses fixed amount + */ + function proposalThreshold() external view returns (uint256); + + /** + * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + * ADMIN + * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + */ + + /** + * @notice Admin function for setting the voting delay. Best to set voting delay to at least a few days, to give + * voters time to make sense of proposals, e.g. 21,600 blocks which should be at least 3 days. + * @param newVotingDelay new voting delay, in blocks + */ + function _setVotingDelay(uint256 newVotingDelay) external; + + /** + * @notice Admin function for setting the voting period + * @param newVotingPeriod new voting period, in blocks + */ + function _setVotingPeriod(uint256 newVotingPeriod) external; + + /** + * @notice Admin function for setting the proposal threshold basis points + * @dev newProposalThresholdBPS must be in [`MIN_PROPOSAL_THRESHOLD_BPS`,`MAX_PROPOSAL_THRESHOLD_BPS`] + * @param newProposalThresholdBPS new proposal threshold + */ + function _setProposalThresholdBPS(uint256 newProposalThresholdBPS) external; + + /** + * @notice Admin function for setting the objection period duration + * @param newObjectionPeriodDurationInBlocks new objection period duration, in blocks + */ + function _setObjectionPeriodDurationInBlocks(uint32 newObjectionPeriodDurationInBlocks) external; + + /** + * @notice Admin function for setting the objection period last minute window + * @param newLastMinuteWindowInBlocks new objection period last minute window, in blocks + */ + function _setLastMinuteWindowInBlocks(uint32 newLastMinuteWindowInBlocks) external; + + /** + * @notice Admin function for setting the proposal updatable period + * @param newProposalUpdatablePeriodInBlocks the new proposal updatable period, in blocks + */ + function _setProposalUpdatablePeriodInBlocks(uint32 newProposalUpdatablePeriodInBlocks) external; + + /** + * @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; + + /** + * @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; + + /** + * @notice Begins transition of vetoer. The newPendingVetoer must call _acceptVetoer to finalize the transfer. + * @param newPendingVetoer New Pending Vetoer + */ + function _setPendingVetoer(address newPendingVetoer) external; + + /** + * @notice Called by the pendingVetoer to accept role and update vetoer + */ + function _acceptVetoer() external; + + /** + * @notice Burns veto priviledges + * @dev Vetoer function destroying veto power forever + */ + function _burnVetoPower() external; + + /** + * @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; + + /** + * @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; + + /** + * @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; + + /** + * @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 + ) external; + + /** + * @notice Withdraws all the ETH in the contract. This is callable only by the admin (timelock). + */ + function _withdraw() external returns (uint256, bool); + + /** + * @notice Admin function for setting the fork period + * @param newForkPeriod the new fork proposal period, in seconds + */ + function _setForkPeriod(uint256 newForkPeriod) external; + + /** + * @notice Admin function for setting the fork threshold + * @param newForkThresholdBPS the new fork proposal threshold, in basis points + */ + function _setForkThresholdBPS(uint256 newForkThresholdBPS) external; + + /** + * @notice Admin function for setting the fork DAO deployer contract + */ + function _setForkDAODeployer(address newForkDAODeployer) external; + + /** + * @notice Admin function for setting the ERC20 tokens that are used when splitting funds to a fork + */ + function _setErc20TokensToIncludeInFork(address[] calldata erc20tokens) external; + + /** + * @notice Admin function for setting the fork escrow contract + */ + function _setForkEscrow(address newForkEscrow) external; + + /** + * @notice Admin function for setting the fork related parameters + * @param forkEscrow_ the fork escrow contract + * @param forkDAODeployer_ the fork dao deployer contract + * @param erc20TokensToIncludeInFork_ the ERC20 tokens used when splitting funds to a fork + * @param forkPeriod_ the period during which it's possible to join a fork after exeuction + * @param forkThresholdBPS_ the threshold required of escrowed nouns in order to execute a fork + */ + function _setForkParams( + address forkEscrow_, + address forkDAODeployer_, + address[] calldata erc20TokensToIncludeInFork_, + uint256 forkPeriod_, + uint256 forkThresholdBPS_ + ) external; + + /** + * @notice Admin function for setting the timelocks and admin + * @param newTimelock the new timelock contract + * @param newTimelockV1 the new timelockV1 contract + * @param newAdmin the new admin address + */ + function _setTimelocksAndAdmin(address newTimelock, address newTimelockV1, address newAdmin) external; + + /** + * @notice Admin function for zeroing out the state variable `voteSnapshotBlockSwitchProposalId` + * @dev We want to zero-out this state slot so we can remove this temporary variable from contract code and + * be ready to reuse this slot. + */ + function _zeroOutVoteSnapshotBlockSwitchProposalId() external; + + /** + * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + * DYNAMIC QUORUM + * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + */ + /** + * @notice Quorum votes required for a specific proposal to succeed + * Differs from `GovernerBravo` which uses fixed amount + */ + function quorumVotes(uint256 proposalId) external view returns (uint256); + + /** + * @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 adjustedTotalSupply_ The adjusted 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 adjustedTotalSupply_, + NounsDAOTypes.DynamicQuorumParams memory params + ) external pure returns (uint256); + + /** + * @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_ + ) external view returns (NounsDAOTypes.DynamicQuorumParams memory); + + /** + * @notice Current min quorum votes using Nouns adjusted total supply + */ + function minQuorumVotes() external view returns (uint256); + + /** + * @notice Current max quorum votes using Nouns adjusted total supply + */ + function maxQuorumVotes() external view returns (uint256); + + /** + * @notice Get all quorum params checkpoints + */ + function quorumParamsCheckpoints() external view returns (NounsDAOTypes.DynamicQuorumParamsCheckpoint[] memory); + + /** + * @notice Get a quorum params checkpoint by its index + */ + function quorumParamsCheckpoints( + uint256 index + ) external view returns (NounsDAOTypes.DynamicQuorumParamsCheckpoint memory); + + /** + * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + * DAO FORK + * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + */ + + /** + * @notice Escrow Nouns to contribute to the fork threshold + * @dev Requires approving the tokenIds or the entire noun token to the DAO contract + * @param tokenIds the tokenIds to escrow. They will be sent to the DAO once the fork threshold is reached and the escrow is closed. + * @param proposalIds array of proposal ids which are the reason for wanting to fork. This will only be used to emit event. + * @param reason the reason for want to fork. This will only be used to emit event. + */ + function escrowToFork(uint256[] calldata tokenIds, uint256[] calldata proposalIds, string calldata reason) external; + + /** + * @notice Withdraw Nouns from the fork escrow. Only possible if the fork has not been executed. + * Only allowed to withdraw tokens that the sender has escrowed. + * @param tokenIds the tokenIds to withdraw + */ + function withdrawFromForkEscrow(uint256[] calldata tokenIds) external; + + /** + * @notice Execute the fork. Only possible if the fork threshold has been met. + * This will deploy a new DAO and send part of the treasury to the new DAO's treasury. + * This will also close the active escrow and all nouns in the escrow belong to the original DAO. + * @return forkTreasury The address of the new DAO's treasury + * @return forkToken The address of the new DAO's token + */ + function executeFork() external returns (address forkTreasury, address forkToken); + + /** + * @notice Joins a fork while a fork is active + * @param tokenIds the tokenIds to send to the DAO in exchange for joining the fork + * @param proposalIds array of proposal ids which are the reason for wanting to fork. This will only be used to emit event. + * @param reason the reason for want to fork. This will only be used to emit event. + */ + function joinFork(uint256[] calldata tokenIds, uint256[] calldata proposalIds, string calldata reason) external; + + /** + * @notice Withdraws nouns from the fork escrow to the treasury after the fork has been executed + * @dev Only the DAO can call this function + * @param tokenIds the tokenIds to withdraw + */ + function withdrawDAONounsFromEscrowToTreasury(uint256[] calldata tokenIds) external; + + /** + * @notice Withdraws nouns from the fork escrow after the fork has been executed to an address other than the treasury + * @dev Only the DAO can call this function + * @param tokenIds the tokenIds to withdraw + * @param to the address to send the nouns to + */ + function withdrawDAONounsFromEscrowIncreasingTotalSupply(uint256[] calldata tokenIds, address to) external; + + /** + * @notice Returns the number of nouns in supply minus nouns owned by the DAO, i.e. held in the treasury or in an + * escrow after it has closed. + * This is used when calculating proposal threshold, quorum, fork threshold & treasury split. + */ + function adjustedTotalSupply() external view returns (uint256); + + /** + * @notice returns the required number of tokens to escrow to trigger a fork + */ + function forkThreshold() external view returns (uint256); + + /** + * @notice Returns the number of tokens currently in escrow, contributing to the fork threshold + */ + function numTokensInForkEscrow() external view returns (uint256); + + /** + * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + * VOTES + * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + */ + + /** + * @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; + + /** + * @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; + + function castRefundableVote(uint256 proposalId, uint8 support, uint32 clientId) external; + + /** + * @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; + + function castRefundableVoteWithReason( + uint256 proposalId, + uint8 support, + string calldata reason, + uint32 clientId + ) external; + + /** + * @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; + + /** + * @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; + + /** + * @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; + + /** + * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + * STATE VARIABLE GETTERS + * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ + */ + + function admin() external view returns (address); + + function implementation() external view returns (address); + + function vetoer() external view returns (address); + + function pendingVetoer() external view returns (address); + + function votingDelay() external view returns (uint256); + + function votingPeriod() external view returns (uint256); + + function proposalThresholdBPS() external view returns (uint256); + + function quorumVotesBPS() external view returns (uint256); + + function proposalCount() external view returns (uint256); + + function timelock() external view returns (INounsDAOExecutor); + + function nouns() external view returns (NounsTokenLike); + + function latestProposalIds(address account) external view returns (uint256); + + function lastMinuteWindowInBlocks() external view returns (uint256); + + function objectionPeriodDurationInBlocks() external view returns (uint256); + + function erc20TokensToIncludeInFork() external view returns (address[] memory); + + function forkEscrow() external view returns (INounsDAOForkEscrow); + + function forkDAODeployer() external view returns (IForkDAODeployer); + + function forkEndTimestamp() external view returns (uint256); + + function forkPeriod() external view returns (uint256); + + function forkThresholdBPS() external view returns (uint256); + + function proposalUpdatablePeriodInBlocks() external view returns (uint256); + + function timelockV1() external view returns (address); + + function voteSnapshotBlockSwitchProposalId() external view returns (uint256); +} diff --git a/packages/nouns-contracts/contracts/libs/ClientRewardsMemoryMapping.sol b/packages/nouns-contracts/contracts/libs/ClientRewardsMemoryMapping.sol new file mode 100644 index 0000000000..84e840c196 --- /dev/null +++ b/packages/nouns-contracts/contracts/libs/ClientRewardsMemoryMapping.sol @@ -0,0 +1,99 @@ +// SPDX-License-Identifier: GPL-3.0 + +/********************************* + * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ * + * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ * + * ░░░░░░█████████░░█████████░░░ * + * ░░░░░░██░░░████░░██░░░████░░░ * + * ░░██████░░░████████░░░████░░░ * + * ░░██░░██░░░████░░██░░░████░░░ * + * ░░██░░██░░░████░░██░░░████░░░ * + * ░░░░░░█████████░░█████████░░░ * + * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ * + * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ * + *********************************/ + +pragma solidity ^0.8.19; + +/** + * @notice A library for short lived in memory mappings. + * This only works when the keys, in this case clientId, are of limited size so that they we can create + * an array in memory for all the possible values + */ +library ClientRewardsMemoryMapping { + struct Mapping { + /// @dev indexes[clientId] returns the index in `values` array where the value for clientId is. + /// zero means it hasn't been initialized yet. + uint32[] indexes; + /// @dev array of values. the first cell (index zero) is kept empty. + ClientBalance[] values; + /// @dev index of the next cell in `values` array which we can allocate for a new clientId + uint32 nextAvailableIndex; + } + + struct ClientBalance { + uint32 clientId; + uint256 balance; + } + + /** + * Returns a new in memory mapping. + * @param maxClientId maximum value for a clientId key + */ + function createMapping(uint32 maxClientId) internal pure returns (Mapping memory m) { + m.indexes = new uint32[](maxClientId + 1); + /// @dev index zero is reserved so allocated one extra cell + m.values = new ClientBalance[](maxClientId + 2); + m.nextAvailableIndex = 1; // 0 is reserved to mean unindexed + } + + /** + * Sets the value for client `clientId` to `balance` + */ + function set(Mapping memory m, uint32 clientId, uint256 balance) internal pure { + uint32 idx = m.indexes[clientId]; + if (idx == 0) { + idx = m.nextAvailableIndex++; + m.indexes[clientId] = idx; + m.values[idx].clientId = clientId; + } + m.values[idx].balance = balance; + } + + /** + * Increases the value of client `clientId` by `balanceDiff` + */ + function inc(Mapping memory m, uint32 clientId, uint256 balanceDiff) internal pure { + uint32 idx = m.indexes[clientId]; + if (idx == 0) { + idx = m.nextAvailableIndex++; + m.indexes[clientId] = idx; + m.values[idx].clientId = clientId; + } + m.values[idx].balance += balanceDiff; + } + + /** + * Returns the current value for client `clientId` + */ + function get(Mapping memory m, uint32 clientId) internal pure returns (uint256 balance) { + uint32 idx = m.indexes[clientId]; + if (idx == 0) return 0; + return m.values[idx].balance; + } + + /** + * Returns the number of key/values stored + */ + function numValues(Mapping memory m) internal pure returns (uint256) { + return m.nextAvailableIndex - 1; + } + + /** + * Returns the idx-th value stored + */ + function getValue(Mapping memory m, uint32 idx) internal pure returns (ClientBalance memory) { + // zero index is unused + return m.values[idx + 1]; + } +} diff --git a/packages/nouns-contracts/contracts/libs/ETHString.sol b/packages/nouns-contracts/contracts/libs/ETHString.sol new file mode 100644 index 0000000000..cf4358d22c --- /dev/null +++ b/packages/nouns-contracts/contracts/libs/ETHString.sol @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: GPL-3.0 + +/********************************* + * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ * + * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ * + * ░░░░░░█████████░░█████████░░░ * + * ░░░░░░██░░░████░░██░░░████░░░ * + * ░░██████░░░████████░░░████░░░ * + * ░░██░░██░░░████░░██░░░████░░░ * + * ░░██░░██░░░████░░██░░░████░░░ * + * ░░░░░░█████████░░█████████░░░ * + * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ * + * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ * + *********************************/ + +pragma solidity ^0.8.19; + +import { Strings } from '@openzeppelin/contracts/utils/Strings.sol'; + +library ETHString { + using Strings for uint256; + + function toETHString(uint256 amount) internal pure returns (string memory result) { + string memory integerPart = (amount / 1 ether).toString(); + uint256 decimalPart = (amount % 1 ether) / 10 ** 16; // 10^16 wei = 0.01 ETH + + if (decimalPart == 0) { + result = string(abi.encodePacked(integerPart, '.00')); + } else if (decimalPart < 10) { + result = string(abi.encodePacked(integerPart, '.0', decimalPart.toString())); + } else { + result = string(abi.encodePacked(integerPart, '.', decimalPart.toString())); + } + } +} diff --git a/packages/nouns-contracts/contracts/libs/GasRefund.sol b/packages/nouns-contracts/contracts/libs/GasRefund.sol new file mode 100644 index 0000000000..e69977801c --- /dev/null +++ b/packages/nouns-contracts/contracts/libs/GasRefund.sol @@ -0,0 +1,51 @@ +// SPDX-License-Identifier: GPL-3.0 + +/********************************* + * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ * + * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ * + * ░░░░░░█████████░░█████████░░░ * + * ░░░░░░██░░░████░░██░░░████░░░ * + * ░░██████░░░████████░░░████░░░ * + * ░░██░░██░░░████░░██░░░████░░░ * + * ░░██░░██░░░████░░██░░░████░░░ * + * ░░░░░░█████████░░█████████░░░ * + * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ * + * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ * + *********************************/ + +pragma solidity ^0.8.19; + +import { SafeERC20 } from '@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol'; +import { IERC20 } from '@openzeppelin/contracts/token/ERC20/IERC20.sol'; + +library GasRefund { + using SafeERC20 for IERC20; + + /// @notice The maximum priority fee used to cap gas refunds + uint256 public constant MAX_REFUND_PRIORITY_FEE = 2 gwei; + + /// @notice The vote refund gas overhead, including 7K for token transfer and 29K for general transaction overhead + uint256 public constant REFUND_BASE_GAS = 36000; + + /// @notice The maximum basefee the DAO will refund + uint256 public constant MAX_REFUND_BASE_FEE = 200 gwei; + + /// @dev refunds gas using the `ethToken` instead of ETH + function refundGas(IERC20 ethToken, uint256 startGas) internal { + unchecked { + uint256 balance = ethToken.balanceOf(address(this)); + 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 = startGas - gasleft() + REFUND_BASE_GAS; + uint256 refundAmount = min(gasPrice * gasUsed, balance); + ethToken.safeTransfer(tx.origin, refundAmount); + } + } + + function min(uint256 a, uint256 b) internal pure returns (uint256) { + return a < b ? a : b; + } +} diff --git a/packages/nouns-contracts/contracts/test/MaliciousVoter.sol b/packages/nouns-contracts/contracts/test/MaliciousVoter.sol index 3e695b104c..55f4349ff3 100644 --- a/packages/nouns-contracts/contracts/test/MaliciousVoter.sol +++ b/packages/nouns-contracts/contracts/test/MaliciousVoter.sol @@ -2,20 +2,15 @@ pragma solidity ^0.8.19; -import { NounsDAOLogicV2 } from '../governance/NounsDAOLogicV2.sol'; +import { INounsDAOLogic } from '../interfaces/INounsDAOLogic.sol'; contract MaliciousVoter { - NounsDAOLogicV2 public dao; + INounsDAOLogic public dao; uint256 public proposalId; uint8 public support; bool useReason; - constructor( - NounsDAOLogicV2 dao_, - uint256 proposalId_, - uint8 support_, - bool useReason_ - ) { + constructor(INounsDAOLogic dao_, uint256 proposalId_, uint8 support_, bool useReason_) { dao = dao_; proposalId = proposalId_; support = support_; diff --git a/packages/nouns-contracts/contracts/test/NounsDAOLogicV1Harness.sol b/packages/nouns-contracts/contracts/test/NounsDAOLogicV1Harness.sol deleted file mode 100644 index acc20c155f..0000000000 --- a/packages/nouns-contracts/contracts/test/NounsDAOLogicV1Harness.sol +++ /dev/null @@ -1,28 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.19; - -import '../governance/NounsDAOLogicV1.sol'; - -contract NounsDAOLogicV1Harness is NounsDAOLogicV1 { - function initialize( - address timelock_, - address nouns_, - address vetoer_, - uint256 votingPeriod_, - uint256 votingDelay_, - uint256 proposalThresholdBPS_, - uint256 quorumVotesBPS_ - ) public override { - require(msg.sender == admin, 'NounsDAO::initialize: admin only'); - require(address(timelock) == address(0), 'NounsDAO::initialize: can only initialize once'); - - timelock = INounsDAOExecutor(timelock_); - nouns = NounsTokenLike(nouns_); - vetoer = vetoer_; - votingPeriod = votingPeriod_; - votingDelay = votingDelay_; - proposalThresholdBPS = proposalThresholdBPS_; - quorumVotesBPS = quorumVotesBPS_; - } -} diff --git a/packages/nouns-contracts/contracts/test/NounsDAOLogicV2Harness.sol b/packages/nouns-contracts/contracts/test/NounsDAOLogicV2Harness.sol deleted file mode 100644 index ade2b2d6e4..0000000000 --- a/packages/nouns-contracts/contracts/test/NounsDAOLogicV2Harness.sol +++ /dev/null @@ -1,32 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.19; - -import '../governance/NounsDAOLogicV2.sol'; - -contract NounsDAOLogicV2Harness is NounsDAOLogicV2 { - function initialize( - address timelock_, - address nouns_, - address vetoer_, - uint256 votingPeriod_, - uint256 votingDelay_, - uint256 proposalThresholdBPS_, - DynamicQuorumParams calldata dynamicQuorumParams_ - ) public override { - require(msg.sender == admin, 'NounsDAO::initialize: admin only'); - require(address(timelock) == address(0), 'NounsDAO::initialize: can only initialize once'); - - timelock = INounsDAOExecutor(timelock_); - nouns = NounsTokenLike(nouns_); - vetoer = vetoer_; - votingPeriod = votingPeriod_; - votingDelay = votingDelay_; - proposalThresholdBPS = proposalThresholdBPS_; - _setDynamicQuorumParams( - dynamicQuorumParams_.minQuorumVotesBPS, - dynamicQuorumParams_.maxQuorumVotesBPS, - dynamicQuorumParams_.quorumCoefficient - ); - } -} diff --git a/packages/nouns-contracts/contracts/test/NounsDAOLogicV3Harness.sol b/packages/nouns-contracts/contracts/test/NounsDAOLogicV3Harness.sol index 42a7901a45..b514f1a006 100644 --- a/packages/nouns-contracts/contracts/test/NounsDAOLogicV3Harness.sol +++ b/packages/nouns-contracts/contracts/test/NounsDAOLogicV3Harness.sol @@ -2,15 +2,15 @@ pragma solidity ^0.8.19; -import '../governance/NounsDAOLogicV3.sol'; -import { NounsDAOV3Admin } from '../governance/NounsDAOV3Admin.sol'; +import '../governance/NounsDAOLogicV4.sol'; +import { NounsDAOAdmin } from '../governance/NounsDAOAdmin.sol'; /** - * @dev A modified version of NounsDAOLogicV3 that exposes the `initialize` function for testing purposes. + * @dev A modified version of NounsDAOLogicV4 that exposes the `initialize` function for testing purposes. * The modification removes bounds checks on parameters, so we can dramatically shorten test scenarios setup. */ -contract NounsDAOLogicV3Harness is NounsDAOLogicV3 { - using NounsDAOV3Admin for StorageV3; +contract NounsDAOLogicV3Harness is NounsDAOLogicV4 { + using NounsDAOAdmin for Storage; function initialize( address timelock_, @@ -34,13 +34,13 @@ contract NounsDAOLogicV3Harness is NounsDAOLogicV3 { ds.forkEscrow = INounsDAOForkEscrow(forkEscrow_); ds.forkDAODeployer = IForkDAODeployer(forkDAODeployer_); ds.vetoer = vetoer_; - _setDynamicQuorumParams( + NounsDAOAdmin._setDynamicQuorumParams( dynamicQuorumParams_.minQuorumVotesBPS, dynamicQuorumParams_.maxQuorumVotesBPS, dynamicQuorumParams_.quorumCoefficient ); - ds._setLastMinuteWindowInBlocks(daoParams_.lastMinuteWindowInBlocks); - ds._setObjectionPeriodDurationInBlocks(daoParams_.objectionPeriodDurationInBlocks); - ds._setProposalUpdatablePeriodInBlocks(daoParams_.proposalUpdatablePeriodInBlocks); + NounsDAOAdmin._setLastMinuteWindowInBlocks(daoParams_.lastMinuteWindowInBlocks); + NounsDAOAdmin._setObjectionPeriodDurationInBlocks(daoParams_.objectionPeriodDurationInBlocks); + NounsDAOAdmin._setProposalUpdatablePeriodInBlocks(daoParams_.proposalUpdatablePeriodInBlocks); } } diff --git a/packages/nouns-contracts/contracts/test/Voter.sol b/packages/nouns-contracts/contracts/test/Voter.sol index 991fc9c5a2..900ce7da63 100644 --- a/packages/nouns-contracts/contracts/test/Voter.sol +++ b/packages/nouns-contracts/contracts/test/Voter.sol @@ -2,23 +2,18 @@ pragma solidity ^0.8.19; -import { NounsDAOLogicV2 } from '../governance/NounsDAOLogicV2.sol'; +import { INounsDAOLogic } from '../interfaces/INounsDAOLogic.sol'; /** * @dev this contract is used to simulate voting via a multisig */ contract Voter { - NounsDAOLogicV2 public dao; + INounsDAOLogic public dao; uint256 public proposalId; uint8 public support; bool useReason; - constructor( - NounsDAOLogicV2 dao_, - uint256 proposalId_, - uint8 support_, - bool useReason_ - ) { + constructor(INounsDAOLogic dao_, uint256 proposalId_, uint8 support_, bool useReason_) { dao = dao_; proposalId = proposalId_; support = support_; diff --git a/packages/nouns-contracts/foundry.toml b/packages/nouns-contracts/foundry.toml index 050e7501dd..bd911cb174 100644 --- a/packages/nouns-contracts/foundry.toml +++ b/packages/nouns-contracts/foundry.toml @@ -3,5 +3,8 @@ src = 'contracts' libs = ['lib', '../../node_modules'] cache_path = 'foundry-cache' out = 'foundry-out' -solc_version = '0.8.19' -fs_permissions = [{ access = "read", path = "./"}] \ No newline at end of file +solc_version = '0.8.23' +fs_permissions = [{ access = "read", path = "./"}] + +[profile.lite] +optimizer = false \ No newline at end of file diff --git a/packages/nouns-contracts/hardhat.config.ts b/packages/nouns-contracts/hardhat.config.ts index 4b641a010e..5162fc66b9 100644 --- a/packages/nouns-contracts/hardhat.config.ts +++ b/packages/nouns-contracts/hardhat.config.ts @@ -14,7 +14,7 @@ dotenv.config(); const config: HardhatUserConfig = { solidity: { - version: '0.8.19', + version: '0.8.23', settings: { optimizer: { enabled: true, diff --git a/packages/nouns-contracts/package.json b/packages/nouns-contracts/package.json index f55e1160b4..a30eea4d90 100644 --- a/packages/nouns-contracts/package.json +++ b/packages/nouns-contracts/package.json @@ -42,7 +42,7 @@ "hardhat": "^2.9.7", "hardhat-abi-exporter": "^2.9.0", "hardhat-gas-reporter": "^1.0.8", - "prettier-plugin-solidity": "^1.0.0-beta.12", + "prettier-plugin-solidity": "^1.2.0", "prompt": "^1.1.0", "shx": "^0.3.3", "ts-node": "^10.0.0", diff --git a/packages/nouns-contracts/script/AuctionHouseV2/DeployAuctionHouseV2Base.s.sol b/packages/nouns-contracts/script/AuctionHouseV2/DeployAuctionHouseV2Base.s.sol new file mode 100644 index 0000000000..ee639462ee --- /dev/null +++ b/packages/nouns-contracts/script/AuctionHouseV2/DeployAuctionHouseV2Base.s.sol @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity ^0.8.19; + +import 'forge-std/Script.sol'; +import { NounsAuctionHouse } from '../../contracts/NounsAuctionHouse.sol'; +import { NounsAuctionHouseV2 } from '../../contracts/NounsAuctionHouseV2.sol'; +import { NounsAuctionHousePreV2Migration } from '../../contracts/NounsAuctionHousePreV2Migration.sol'; +import { OptimizedScript } from '../OptimizedScript.s.sol'; + +abstract contract DeployAuctionHouseV2Base is OptimizedScript { + NounsAuctionHouse public immutable auctionV1; + + constructor(address _auctionHouseProxy) { + auctionV1 = NounsAuctionHouse(payable(_auctionHouseProxy)); + } + + function run() public returns (NounsAuctionHouseV2 newLogic, NounsAuctionHousePreV2Migration migratorLogic) { + requireDefaultProfile(); + uint256 deployerKey = vm.envUint('DEPLOYER_PRIVATE_KEY'); + + vm.startBroadcast(deployerKey); + + newLogic = new NounsAuctionHouseV2(auctionV1.nouns(), auctionV1.weth(), auctionV1.duration()); + migratorLogic = new NounsAuctionHousePreV2Migration(); + + vm.stopBroadcast(); + } +} diff --git a/packages/nouns-contracts/script/AuctionHouseV2/DeployAuctionHouseV2Mainnet.s.sol b/packages/nouns-contracts/script/AuctionHouseV2/DeployAuctionHouseV2Mainnet.s.sol new file mode 100644 index 0000000000..329bca88c0 --- /dev/null +++ b/packages/nouns-contracts/script/AuctionHouseV2/DeployAuctionHouseV2Mainnet.s.sol @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity ^0.8.19; + +import { DeployAuctionHouseV2Base } from './DeployAuctionHouseV2Base.s.sol'; + +contract DeployAuctionHouseV2Mainnet is DeployAuctionHouseV2Base { + address constant AUCTION_HOUSE_PROXY_MAINNET = 0x830BD73E4184ceF73443C15111a1DF14e495C706; + + constructor() DeployAuctionHouseV2Base(AUCTION_HOUSE_PROXY_MAINNET) {} +} \ No newline at end of file diff --git a/packages/nouns-contracts/script/AuctionHouseV2/DeployAuctionHouseV2Sepolia.s.sol b/packages/nouns-contracts/script/AuctionHouseV2/DeployAuctionHouseV2Sepolia.s.sol new file mode 100644 index 0000000000..2f8423b110 --- /dev/null +++ b/packages/nouns-contracts/script/AuctionHouseV2/DeployAuctionHouseV2Sepolia.s.sol @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity ^0.8.19; + +import { DeployAuctionHouseV2Base } from './DeployAuctionHouseV2Base.s.sol'; + +contract DeployAuctionHouseV2Sepolia is DeployAuctionHouseV2Base { + address constant AUCTION_HOUSE_SEPOLIA = 0xf459b7573a9c2B37eF21F2f7a1a96339E343CdD8; + + constructor() DeployAuctionHouseV2Base(AUCTION_HOUSE_SEPOLIA) {} +} \ No newline at end of file diff --git a/packages/nouns-contracts/script/DAOUpgrade/DeployDAOLogicOptimized.s.sol b/packages/nouns-contracts/script/DAOUpgrade/DeployDAOLogicOptimized.s.sol new file mode 100644 index 0000000000..e05f607d85 --- /dev/null +++ b/packages/nouns-contracts/script/DAOUpgrade/DeployDAOLogicOptimized.s.sol @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity ^0.8.19; + +import 'forge-std/Script.sol'; +import { OptimizedScript } from '../OptimizedScript.s.sol'; +import { NounsDAOLogicV4 } from '../../contracts/governance/NounsDAOLogicV4.sol'; + +contract DeployDAOLogicOptimized is OptimizedScript { + function run() public returns (NounsDAOLogicV4 daoLogic) { + requireDefaultProfile(); + + uint256 deployerKey = vm.envUint('DEPLOYER_PRIVATE_KEY'); + vm.startBroadcast(deployerKey); + + daoLogic = new NounsDAOLogicV4(); + + vm.stopBroadcast(); + } +} diff --git a/packages/nouns-contracts/script/DAOV3p1/ProposeDAOV3p1UpgradeMainnet.s.sol b/packages/nouns-contracts/script/DAOUpgrade/ProposeDAOUpgradeMainnet.s.sol similarity index 96% rename from packages/nouns-contracts/script/DAOV3p1/ProposeDAOV3p1UpgradeMainnet.s.sol rename to packages/nouns-contracts/script/DAOUpgrade/ProposeDAOUpgradeMainnet.s.sol index aa51ad7fdd..07562837d3 100644 --- a/packages/nouns-contracts/script/DAOV3p1/ProposeDAOV3p1UpgradeMainnet.s.sol +++ b/packages/nouns-contracts/script/DAOUpgrade/ProposeDAOUpgradeMainnet.s.sol @@ -13,7 +13,7 @@ interface NounsDAO { ) external returns (uint256); } -contract ProposeDAOV3p1UpgradeMainnet is Script { +contract ProposeDAOUpgradeMainnet is Script { NounsDAO public constant NOUNS_DAO_PROXY_MAINNET = NounsDAO(0x6f3E6272A167e8AcCb32072d08E0957F9c79223d); function run() public returns (uint256 proposalId) { diff --git a/packages/nouns-contracts/script/DAOV3p1/DeployDAOV3LogicMainnet.s.sol b/packages/nouns-contracts/script/DAOV3p1/DeployDAOV3LogicMainnet.s.sol deleted file mode 100644 index 514d3a0136..0000000000 --- a/packages/nouns-contracts/script/DAOV3p1/DeployDAOV3LogicMainnet.s.sol +++ /dev/null @@ -1,16 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0 -pragma solidity ^0.8.19; - -import 'forge-std/Script.sol'; -import { NounsDAOLogicV3 } from '../../contracts/governance/NounsDAOLogicV3.sol'; - -contract DeployDAOV3LogicMainnet is Script { - function run() public returns (NounsDAOLogicV3 daoLogic) { - uint256 deployerKey = vm.envUint('DEPLOYER_PRIVATE_KEY'); - vm.startBroadcast(deployerKey); - - daoLogic = new NounsDAOLogicV3(); - - vm.stopBroadcast(); - } -} diff --git a/packages/nouns-contracts/script/DeployDAOV3NewContractsBase.s.sol b/packages/nouns-contracts/script/DeployDAOV3NewContractsBase.s.sol index 738428a1e3..ab391e0c3d 100644 --- a/packages/nouns-contracts/script/DeployDAOV3NewContractsBase.s.sol +++ b/packages/nouns-contracts/script/DeployDAOV3NewContractsBase.s.sol @@ -4,7 +4,7 @@ pragma solidity ^0.8.15; import 'forge-std/Script.sol'; import { NounsDAOExecutorV2 } from '../contracts/governance/NounsDAOExecutorV2.sol'; import { NounsDAOExecutorV2Test } from '../contracts/test/NounsDAOExecutorHarness.sol'; -import { NounsDAOLogicV3 } from '../contracts/governance/NounsDAOLogicV3.sol'; +import { NounsDAOLogicV4 } from '../contracts/governance/NounsDAOLogicV4.sol'; import { NounsDAOExecutorProxy } from '../contracts/governance/NounsDAOExecutorProxy.sol'; import { INounsDAOExecutor } from '../contracts/governance/NounsDAOInterfaces.sol'; import { NounsDAOForkEscrow } from '../contracts/governance/fork/NounsDAOForkEscrow.sol'; @@ -48,7 +48,7 @@ contract DeployDAOV3NewContractsBase is Script { returns ( NounsDAOForkEscrow forkEscrow, ForkDAODeployer forkDeployer, - NounsDAOLogicV3 daoV3Impl, + NounsDAOLogicV4 daoImpl, NounsDAOExecutorV2 timelockV2, ERC20Transferer erc20Transferer ) @@ -57,7 +57,7 @@ contract DeployDAOV3NewContractsBase is Script { vm.startBroadcast(deployerKey); - (forkEscrow, forkDeployer, daoV3Impl, timelockV2, erc20Transferer) = deployNewContracts(); + (forkEscrow, forkDeployer, daoImpl, timelockV2, erc20Transferer) = deployNewContracts(); vm.stopBroadcast(); } @@ -67,7 +67,7 @@ contract DeployDAOV3NewContractsBase is Script { returns ( NounsDAOForkEscrow forkEscrow, ForkDAODeployer forkDeployer, - NounsDAOLogicV3 daoV3Impl, + NounsDAOLogicV4 daoImpl, NounsDAOExecutorV2 timelockV2, ERC20Transferer erc20Transferer ) @@ -91,7 +91,7 @@ contract DeployDAOV3NewContractsBase is Script { FORK_DAO_PROPOSAL_THRESHOLD_BPS, FORK_DAO_QUORUM_VOTES_BPS ); - daoV3Impl = new NounsDAOLogicV3(); + daoImpl = new NounsDAOLogicV4(); timelockV2 = deployAndInitTimelockV2(address(timelockV2Impl)); erc20Transferer = new ERC20Transferer(); } diff --git a/packages/nouns-contracts/script/OptimizedScript.s.sol b/packages/nouns-contracts/script/OptimizedScript.s.sol new file mode 100644 index 0000000000..12c50ed25c --- /dev/null +++ b/packages/nouns-contracts/script/OptimizedScript.s.sol @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity ^0.8.19; + +import 'forge-std/Script.sol'; + +abstract contract OptimizedScript is Script { + function requireDefaultProfile() internal { + string memory foundryProfile = vm.envOr('FOUNDRY_PROFILE', string('default')); + console.log('foundry profile: ', foundryProfile); + require( + keccak256(abi.encodePacked(foundryProfile)) == keccak256(abi.encodePacked('default')), + 'foundry profile must be default to deploy optimized contracts' + ); + } +} \ No newline at end of file diff --git a/packages/nouns-contracts/script/ProposeDAOV3UpgradeMainnet.s.sol b/packages/nouns-contracts/script/ProposeDAOV3UpgradeMainnet.s.sol deleted file mode 100644 index 0cd4a28e06..0000000000 --- a/packages/nouns-contracts/script/ProposeDAOV3UpgradeMainnet.s.sol +++ /dev/null @@ -1,166 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0 -pragma solidity ^0.8.15; - -import 'forge-std/Script.sol'; -import { NounsDAOForkEscrow } from '../contracts/governance/fork/NounsDAOForkEscrow.sol'; -import { ForkDAODeployer } from '../contracts/governance/fork/ForkDAODeployer.sol'; -import { IERC20 } from '@openzeppelin/contracts/token/ERC20/IERC20.sol'; - -interface NounsDAO { - function propose( - address[] memory targets, - uint256[] memory values, - string[] memory signatures, - bytes[] memory calldatas, - string memory description - ) external returns (uint256); -} - -contract ProposeDAOV3UpgradeMainnet is Script { - NounsDAO public constant NOUNS_DAO_PROXY_MAINNET = NounsDAO(0x6f3E6272A167e8AcCb32072d08E0957F9c79223d); - address public constant NOUNS_TIMELOCK_V1_MAINNET = 0x0BC3807Ec262cB779b38D65b38158acC3bfedE10; - - uint256 public constant ETH_TO_SEND_TO_NEW_TIMELOCK = 2500 ether; - uint256 public constant STETH_BUFFER = 5000 ether; - uint256 public constant FORK_PERIOD = 7 days; - uint256 public constant FORK_THRESHOLD_BPS = 2000; - - address public constant STETH_MAINNET = 0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84; - address public constant WSTETH_MAINNET = 0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0; - address public constant RETH_MAINNET = 0xae78736Cd615f374D3085123A210448E74Fc6393; - address public constant USDC_MAINNET = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48; - - address public constant AUCTION_HOUSE_PROXY_MAINNET = 0x830BD73E4184ceF73443C15111a1DF14e495C706; - address public constant AUCTION_HOUSE_PROXY_ADMIN_MAINNET = 0xC1C119932d78aB9080862C5fcb964029f086401e; - address public constant NOUNS_TOKEN_MAINNET = 0x9C8fF314C9Bc7F6e59A9d9225Fb22946427eDC03; - address public constant DESCRIPTOR_MAINNET = 0x6229c811D04501523C6058bfAAc29c91bb586268; - - function run() public returns (uint256 proposalId) { - uint256 proposerKey = vm.envUint('PROPOSER_KEY'); - address daoV3Implementation = vm.envAddress('DAO_V3_IMPL'); - address timelockV2 = vm.envAddress('TIMELOCK_V2'); - address forkEscrow = vm.envAddress('FORK_ESCROW'); - address forkDeployer = vm.envAddress('FORK_DEPLOYER'); - - string memory description = vm.readFile(vm.envString('PROPOSAL_DESCRIPTION_FILE')); - - address[] memory erc20TokensToIncludeInFork = new address[](4); - erc20TokensToIncludeInFork[0] = STETH_MAINNET; - erc20TokensToIncludeInFork[1] = WSTETH_MAINNET; - erc20TokensToIncludeInFork[2] = RETH_MAINNET; - erc20TokensToIncludeInFork[3] = USDC_MAINNET; - - vm.startBroadcast(proposerKey); - - proposalId = propose( - NOUNS_DAO_PROXY_MAINNET, - daoV3Implementation, - timelockV2, - ETH_TO_SEND_TO_NEW_TIMELOCK, - forkEscrow, - forkDeployer, - erc20TokensToIncludeInFork, - description - ); - console.log('Proposed proposalId: %d', proposalId); - - vm.stopBroadcast(); - } - - function propose( - NounsDAO daoProxy, - address daoV3Implementation, - address timelockV2, - uint256 ethToSendToNewTimelock, - address forkEscrow, - address forkDeployer, - address[] memory erc20TokensToIncludeInFork, - string memory description - ) internal returns (uint256 proposalId) { - // We are limited to 10 txs per proposal, see `proposalMaxOperations` in NounsDAOV3Proposals.sol - uint8 numTxs = 10; - address[] memory targets = new address[](numTxs); - uint256[] memory values = new uint256[](numTxs); - string[] memory signatures = new string[](numTxs); - bytes[] memory calldatas = new bytes[](numTxs); - - // Can't send the entire ETH balance because we can't reference self.balance - // Would also be good to leave some ETH in case of queued proposals - // For both reasons, we will first sent a chunk of ETH, and send the rest in a followup proposal - uint256 i = 0; - targets[i] = timelockV2; - values[i] = ethToSendToNewTimelock; - signatures[i] = ''; - calldatas[i] = ''; - - // Upgrade to DAO V3 - i++; - targets[i] = address(daoProxy); - values[i] = 0; - signatures[i] = '_setImplementation(address)'; - calldatas[i] = abi.encode(daoV3Implementation); - - i++; - targets[i] = address(daoProxy); - values[i] = 0; - signatures[i] = '_setForkParams(address,address,address[],uint256,uint256)'; - calldatas[i] = abi.encode( - forkEscrow, - forkDeployer, - erc20TokensToIncludeInFork, - FORK_PERIOD, - FORK_THRESHOLD_BPS - ); - - i++; - targets[i] = address(daoProxy); - values[i] = 0; - signatures[i] = '_setVoteSnapshotBlockSwitchProposalId()'; - calldatas[i] = ''; - - i++; - targets[i] = AUCTION_HOUSE_PROXY_MAINNET; - values[i] = 0; - signatures[i] = 'transferOwnership(address)'; - calldatas[i] = abi.encode(timelockV2); - - // Keeping a buffer of stETH in timelockV1 for proposals that might need to spend stETH after the migration - uint256 stETHToSend = IERC20(STETH_MAINNET).balanceOf(NOUNS_TIMELOCK_V1_MAINNET) - STETH_BUFFER; - - i++; - targets[i] = STETH_MAINNET; - values[i] = 0; - signatures[i] = 'transfer(address,uint256)'; - calldatas[i] = abi.encode(timelockV2, stETHToSend); - - // Change nouns token owner - i++; - targets[i] = NOUNS_TOKEN_MAINNET; - values[i] = 0; - signatures[i] = 'transferOwnership(address)'; - calldatas[i] = abi.encode(timelockV2); - - // Change descriptor owner - i++; - targets[i] = DESCRIPTOR_MAINNET; - values[i] = 0; - signatures[i] = 'transferOwnership(address)'; - calldatas[i] = abi.encode(timelockV2); - - // Change auction house proxy admin owner - i++; - targets[i] = AUCTION_HOUSE_PROXY_ADMIN_MAINNET; - values[i] = 0; - signatures[i] = 'transferOwnership(address)'; - calldatas[i] = abi.encode(timelockV2); - - // This must be the last transaction, because starting now, execution will be from timelockV2 - i++; - targets[i] = address(daoProxy); - values[i] = 0; - signatures[i] = '_setTimelocksAndAdmin(address,address,address)'; - calldatas[i] = abi.encode(timelockV2, NOUNS_TIMELOCK_V1_MAINNET, timelockV2); - - proposalId = daoProxy.propose(targets, values, signatures, calldatas, description); - } -} diff --git a/packages/nouns-contracts/script/ProposeDAOV3UpgradeTestnet.s.sol b/packages/nouns-contracts/script/ProposeDAOV3UpgradeTestnet.s.sol deleted file mode 100644 index 13d7fb45e8..0000000000 --- a/packages/nouns-contracts/script/ProposeDAOV3UpgradeTestnet.s.sol +++ /dev/null @@ -1,180 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0 -pragma solidity ^0.8.15; - -import 'forge-std/Script.sol'; -import { NounsDAOForkEscrow } from '../contracts/governance/fork/NounsDAOForkEscrow.sol'; -import { ForkDAODeployer } from '../contracts/governance/fork/ForkDAODeployer.sol'; - -interface NounsDAO { - function propose( - address[] memory targets, - uint256[] memory values, - string[] memory signatures, - bytes[] memory calldatas, - string memory description - ) external returns (uint256); -} - -abstract contract ProposeDAOV3UpgradeTestnet is Script { - uint256 public constant ETH_TO_SEND_TO_NEW_TIMELOCK = 0.001 ether; - uint256 public constant FORK_PERIOD = 1 hours; - uint256 public constant FORK_THRESHOLD_BPS = 2000; - - NounsDAO public immutable daoProxyContract; - address public immutable timelockV1; - address public immutable auctionHouseProxy; - address public immutable stETH; - - constructor( - NounsDAO daoProxy_, - address timelockV1_, - address auctionHouseProxy_, - address stETH_ - ) { - daoProxyContract = daoProxy_; - timelockV1 = timelockV1_; - auctionHouseProxy = auctionHouseProxy_; - stETH = stETH_; - } - - function run() public returns (uint256 proposalId) { - uint256 proposerKey = vm.envUint('PROPOSER_KEY'); - address daoV3Implementation = vm.envAddress('DAO_V3_IMPL'); - address timelockV2 = vm.envAddress('TIMELOCK_V2'); - address forkEscrow = vm.envAddress('FORK_ESCROW'); - address forkDeployer = vm.envAddress('FORK_DEPLOYER'); - address erc20Transferer = vm.envAddress('ERC20_TRANSFERER'); - - string memory description = vm.readFile(vm.envString('PROPOSAL_DESCRIPTION_FILE')); - - address[] memory erc20TokensToIncludeInFork = new address[](1); - erc20TokensToIncludeInFork[0] = stETH; - - vm.startBroadcast(proposerKey); - - proposalId = propose( - daoProxyContract, - daoV3Implementation, - timelockV2, - ETH_TO_SEND_TO_NEW_TIMELOCK, - erc20Transferer, - forkEscrow, - forkDeployer, - erc20TokensToIncludeInFork, - description - ); - console.log('Proposed proposalId: %d', proposalId); - - vm.stopBroadcast(); - } - - function propose( - NounsDAO daoProxy, - address daoV3Implementation, - address timelockV2, - uint256 ethToSendToNewTimelock, - address erc20Transferer, - address forkEscrow, - address forkDeployer, - address[] memory erc20TokensToIncludeInFork, - string memory description - ) internal returns (uint256 proposalId) { - uint8 numTxs = 8; - address[] memory targets = new address[](numTxs); - uint256[] memory values = new uint256[](numTxs); - string[] memory signatures = new string[](numTxs); - bytes[] memory calldatas = new bytes[](numTxs); - - // Can't send the entire ETH balance because we can't reference self.balance - // Would also be good to leave some ETH in case of queued proposals - // For both reasons, we will first sent a chunk of ETH, and send the rest in a followup proposal - uint256 i = 0; - targets[i] = timelockV2; - values[i] = ethToSendToNewTimelock; - signatures[i] = ''; - calldatas[i] = ''; - - // Upgrade to DAO V3 - i++; - targets[i] = address(daoProxy); - values[i] = 0; - signatures[i] = '_setImplementation(address)'; - calldatas[i] = abi.encode(daoV3Implementation); - - i++; - targets[i] = address(daoProxy); - values[i] = 0; - signatures[i] = '_setForkParams(address,address,address[],uint256,uint256)'; - calldatas[i] = abi.encode( - forkEscrow, - forkDeployer, - erc20TokensToIncludeInFork, - FORK_PERIOD, - FORK_THRESHOLD_BPS - ); - - i++; - targets[i] = address(daoProxy); - values[i] = 0; - signatures[i] = '_setVoteSnapshotBlockSwitchProposalId()'; - calldatas[i] = ''; - - i++; - targets[i] = auctionHouseProxy; - values[i] = 0; - signatures[i] = 'transferOwnership(address)'; - calldatas[i] = abi.encode(timelockV2); - - i++; - targets[i] = stETH; - values[i] = 0; - signatures[i] = 'approve(address,uint256)'; - calldatas[i] = abi.encode(erc20Transferer, type(uint256).max); - - i++; - targets[i] = erc20Transferer; - values[i] = 0; - signatures[i] = 'transferEntireBalance(address,address)'; - calldatas[i] = abi.encode(stETH, timelockV2); - - i++; - targets[i] = address(daoProxy); - values[i] = 0; - signatures[i] = '_setTimelocksAndAdmin(address,address,address)'; - calldatas[i] = abi.encode(timelockV2, timelockV1, timelockV2); - - proposalId = daoProxy.propose(targets, values, signatures, calldatas, description); - } -} - -contract ProposeDAOV3UpgradeGoerli is ProposeDAOV3UpgradeTestnet { - NounsDAO public constant NOUNS_DAO_PROXY_GOERLI = NounsDAO(0x9e6D4B42b8Dc567AC4aeCAB369Eb9a3156dF095C); - address public constant NOUNS_TIMELOCK_V1_GOERLI = 0xADa0F1A73D1df49477fa41C7F8476F9eA5aB115f; - address public constant AUCTION_HOUSE_PROXY_GOERLI = 0x17e8512851Db9F04164Aa54A6e62f368acCF9D0c; - address public constant STETH_GOERLI = 0x1643E812aE58766192Cf7D2Cf9567dF2C37e9B7F; - - constructor() - ProposeDAOV3UpgradeTestnet( - NOUNS_DAO_PROXY_GOERLI, - NOUNS_TIMELOCK_V1_GOERLI, - AUCTION_HOUSE_PROXY_GOERLI, - STETH_GOERLI - ) - {} -} - -contract ProposeDAOV3UpgradeSepolia is ProposeDAOV3UpgradeTestnet { - NounsDAO public constant NOUNS_DAO_PROXY_SEPOLIA = NounsDAO(0x35d2670d7C8931AACdd37C89Ddcb0638c3c44A57); - address public constant NOUNS_TIMELOCK_V1_SEPOLIA = 0x332db58b51393f3a6b28d4DD8964234967e1aD33; - address public constant AUCTION_HOUSE_PROXY_SEPOLIA = 0x488609b7113FCf3B761A05956300d605E8f6BcAf; - address public constant STETH_SEPOLIA = 0xf16e3ab44cC450fCbe5E890322Ee715f3f7eAC29; // ERC20Mock - - constructor() - ProposeDAOV3UpgradeTestnet( - NOUNS_DAO_PROXY_SEPOLIA, - NOUNS_TIMELOCK_V1_SEPOLIA, - AUCTION_HOUSE_PROXY_SEPOLIA, - STETH_SEPOLIA - ) - {} -} diff --git a/packages/nouns-contracts/script/ProposeENSReverseLookupConfigMainnet.s.sol b/packages/nouns-contracts/script/ProposeENSReverseLookupConfigMainnet.s.sol index 9a906952a9..1f27a533a4 100644 --- a/packages/nouns-contracts/script/ProposeENSReverseLookupConfigMainnet.s.sol +++ b/packages/nouns-contracts/script/ProposeENSReverseLookupConfigMainnet.s.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.15; import 'forge-std/Script.sol'; -import { NounsDAOLogicV3 } from '../contracts/governance/NounsDAOLogicV3.sol'; +import { INounsDAOLogic } from '../contracts/interfaces/INounsDAOLogic.sol'; /** * @notice Submits a proposal to configure the ENS reverse lookup for nouns.eth. @@ -10,8 +10,8 @@ import { NounsDAOLogicV3 } from '../contracts/governance/NounsDAOLogicV3.sol'; * the msg.sender to ENS. */ contract ProposeENSReverseLookupConfigMainnet is Script { - NounsDAOLogicV3 public constant NOUNS_DAO_PROXY_MAINNET = - NounsDAOLogicV3(payable(0x6f3E6272A167e8AcCb32072d08E0957F9c79223d)); + INounsDAOLogic public constant NOUNS_DAO_PROXY_MAINNET = + INounsDAOLogic(payable(0x6f3E6272A167e8AcCb32072d08E0957F9c79223d)); address public constant ENS_REVERSE_REGISTRAR_MAINNET = 0xa58E81fe9b61B5c3fE2AFD33CF304c454AbFc7Cb; function run() public returns (uint256 proposalId) { @@ -27,7 +27,7 @@ contract ProposeENSReverseLookupConfigMainnet is Script { } function propose( - NounsDAOLogicV3 daoProxy, + INounsDAOLogic daoProxy, address reverseRegistrar, string memory description ) internal returns (uint256 proposalId) { diff --git a/packages/nouns-contracts/script/ProposeTimelockMigrationCleanupMainnet.s.sol b/packages/nouns-contracts/script/ProposeTimelockMigrationCleanupMainnet.s.sol index c424e4fa41..e7cf65eff7 100644 --- a/packages/nouns-contracts/script/ProposeTimelockMigrationCleanupMainnet.s.sol +++ b/packages/nouns-contracts/script/ProposeTimelockMigrationCleanupMainnet.s.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.15; import 'forge-std/Script.sol'; -import { NounsDAOLogicV3 } from '../contracts/governance/NounsDAOLogicV3.sol'; +import { INounsDAOLogic } from '../contracts/interfaces/INounsDAOLogic.sol'; import { IERC20 } from '@openzeppelin/contracts/token/ERC20/IERC20.sol'; /** @@ -11,8 +11,8 @@ import { IERC20 } from '@openzeppelin/contracts/token/ERC20/IERC20.sol'; * proposal has hit that limit. */ contract ProposeTimelockMigrationCleanupMainnet is Script { - NounsDAOLogicV3 public constant NOUNS_DAO_PROXY_MAINNET = - NounsDAOLogicV3(payable(0x6f3E6272A167e8AcCb32072d08E0957F9c79223d)); + INounsDAOLogic public constant NOUNS_DAO_PROXY_MAINNET = + INounsDAOLogic(payable(0x6f3E6272A167e8AcCb32072d08E0957F9c79223d)); address public constant NOUNS_TIMELOCK_V1_MAINNET = 0x0BC3807Ec262cB779b38D65b38158acC3bfedE10; address public constant LILNOUNS_MAINNET = 0x4b10701Bfd7BFEdc47d50562b76b436fbB5BdB3B; address public constant TOKEN_BUYER_MAINNET = 0x4f2aCdc74f6941390d9b1804faBc3E780388cfe5; @@ -44,7 +44,7 @@ contract ProposeTimelockMigrationCleanupMainnet is Script { } function propose( - NounsDAOLogicV3 daoProxy, + INounsDAOLogic daoProxy, address timelockV1, address timelockV2, address erc20Transferer, diff --git a/packages/nouns-contracts/script/Rewards/DeployRewardsBase.s.sol b/packages/nouns-contracts/script/Rewards/DeployRewardsBase.s.sol new file mode 100644 index 0000000000..7879ea0c74 --- /dev/null +++ b/packages/nouns-contracts/script/Rewards/DeployRewardsBase.s.sol @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity ^0.8.19; + +import 'forge-std/Script.sol'; +import { OptimizedScript } from '../OptimizedScript.s.sol'; +import { Rewards } from '../../contracts/client-incentives/Rewards.sol'; +import { INounsDAOLogic } from '../../contracts/interfaces/INounsDAOLogic.sol'; +import { INounsAuctionHouseV2 } from '../../contracts/interfaces/INounsAuctionHouseV2.sol'; +import { NounsClientTokenDescriptor } from '../../contracts/client-incentives/NounsClientTokenDescriptor.sol'; +import { RewardsDeployer } from './RewardsDeployer.sol'; + +abstract contract DeployRewardsBase is OptimizedScript { + function runInternal( + INounsDAOLogic dao, + INounsAuctionHouseV2 auctionHouse, + address admin, + address ethToken + ) internal returns (Rewards rewards) { + requireDefaultProfile(); + + uint256 deployerKey = vm.envUint('DEPLOYER_PRIVATE_KEY'); + + vm.startBroadcast(deployerKey); + + rewards = RewardsDeployer.deployRewards({ + dao: dao, + admin: admin, + auctionHouse: address(auctionHouse), + erc20: ethToken, + descriptor: address(new NounsClientTokenDescriptor()) + }); + + vm.stopBroadcast(); + } +} diff --git a/packages/nouns-contracts/script/Rewards/DeployRewardsMainnet.s.sol b/packages/nouns-contracts/script/Rewards/DeployRewardsMainnet.s.sol new file mode 100644 index 0000000000..53720fb436 --- /dev/null +++ b/packages/nouns-contracts/script/Rewards/DeployRewardsMainnet.s.sol @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity ^0.8.19; + +import { DeployRewardsBase } from './DeployRewardsBase.s.sol'; +import { Rewards } from '../../contracts/client-incentives/Rewards.sol'; +import { INounsDAOLogic } from '../../contracts/interfaces/INounsDAOLogic.sol'; +import { INounsAuctionHouseV2 } from '../../contracts/interfaces/INounsAuctionHouseV2.sol'; + +contract DeployRewardsMainnet is DeployRewardsBase { + address constant AUCTION_HOUSE_MAINNET = 0x830BD73E4184ceF73443C15111a1DF14e495C706; + address constant DAO_PROXY_MAINNET = 0x6f3E6272A167e8AcCb32072d08E0957F9c79223d; + address constant VERBS_SAFE_MAINNET = 0x1020E5b6dB4382A93dab447AE9a310D24404962b; + address constant WETH_MAINNET = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2; + + function run() public returns (Rewards rewards) { + return + super.runInternal({ + dao: INounsDAOLogic(DAO_PROXY_MAINNET), + auctionHouse: INounsAuctionHouseV2(AUCTION_HOUSE_MAINNET), + admin: VERBS_SAFE_MAINNET, + ethToken: WETH_MAINNET + }); + } +} diff --git a/packages/nouns-contracts/script/Rewards/DeployRewardsSepolia.s.sol b/packages/nouns-contracts/script/Rewards/DeployRewardsSepolia.s.sol new file mode 100644 index 0000000000..34aaac38f6 --- /dev/null +++ b/packages/nouns-contracts/script/Rewards/DeployRewardsSepolia.s.sol @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity ^0.8.19; + +import { DeployRewardsBase } from './DeployRewardsBase.s.sol'; +import { Rewards } from '../../contracts/client-incentives/Rewards.sol'; +import { INounsDAOLogic } from '../../contracts/interfaces/INounsDAOLogic.sol'; +import { INounsAuctionHouseV2 } from '../../contracts/interfaces/INounsAuctionHouseV2.sol'; + +contract DeployRewardsSepolia is DeployRewardsBase { + address constant AUCTION_HOUSE_SEPOLIA = 0xf459b7573a9c2B37eF21F2f7a1a96339E343CdD8; + address constant DAO_PROXY_SEPOLIA = 0xDefBf39D0E251fc058fF44B96D40Cf3347596EB9; + address constant VERBS_SAFE_SEPOLIA = 0x6819e97114203100d38D3D7ec214Bc3EBa6d5a0B; + address constant MOCK_ETH_TOKEN_SEPOLIA = 0x7f96dAEF4A54F6A52613d6272560C2BD25e913B8; + + function run() public returns (Rewards rewards) { + return + super.runInternal({ + dao: INounsDAOLogic(DAO_PROXY_SEPOLIA), + auctionHouse: INounsAuctionHouseV2(AUCTION_HOUSE_SEPOLIA), + admin: VERBS_SAFE_SEPOLIA, + ethToken: MOCK_ETH_TOKEN_SEPOLIA + }); + } +} diff --git a/packages/nouns-contracts/script/Rewards/RewardsDeployer.sol b/packages/nouns-contracts/script/Rewards/RewardsDeployer.sol new file mode 100644 index 0000000000..f652f78284 --- /dev/null +++ b/packages/nouns-contracts/script/Rewards/RewardsDeployer.sol @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity ^0.8.19; + +import { INounsDAOLogic } from '../../contracts/interfaces/INounsDAOLogic.sol'; +import { Rewards } from '../../contracts/client-incentives/Rewards.sol'; +import { RewardsProxy } from '../../contracts/client-incentives/RewardsProxy.sol'; + +library RewardsDeployer { + function deployRewards( + INounsDAOLogic dao, + address admin, + address auctionHouse, + address erc20, + address descriptor + ) internal returns (Rewards) { + Rewards rewardsLogic = new Rewards(address(dao), auctionHouse); + bytes memory initCallData = abi.encodeWithSignature( + 'initialize(address,address,address,address)', + address(dao.timelock()), + admin, + erc20, + descriptor + ); + + RewardsProxy proxy = new RewardsProxy(address(rewardsLogic), initCallData); + return Rewards(address(proxy)); + } +} diff --git a/packages/nouns-contracts/src/index.ts b/packages/nouns-contracts/src/index.ts index 4aec15876f..ea357c8303 100644 --- a/packages/nouns-contracts/src/index.ts +++ b/packages/nouns-contracts/src/index.ts @@ -2,17 +2,13 @@ export { default as NounsTokenABI } from '../abi/contracts/NounsToken.sol/NounsT export { default as NounsAuctionHouseABI } from '../abi/contracts/NounsAuctionHouse.sol/NounsAuctionHouse.json'; export { default as NounsDescriptorABI } from '../abi/contracts/NounsDescriptor.sol/NounsDescriptor.json'; export { default as NounsSeederABI } from '../abi/contracts/NounsSeeder.sol/NounsSeeder.json'; -export { default as NounsDAOABI } from '../abi/contracts/governance/NounsDAOLogicV1.sol/NounsDAOLogicV1.json'; -export { default as NounsDAOV2ABI } from '../abi/contracts/governance/NounsDAOLogicV2.sol/NounsDAOLogicV2.json'; -export { default as NounsDAOV3ABI } from '../abi/contracts/governance/NounsDAOLogicV3.sol/NounsDAOLogicV3.json'; +export { default as NounsDAOV3ABI } from '../abi/contracts/governance/NounsDAOLogicV4.json'; export { default as NounsDAODataABI } from '../abi/contracts/governance/data/NounsDAOData.sol/NounsDAOData.json'; export { default as NounsDAOExecutorV2ABI } from '../abi/contracts/governance/NounsDAOExecutorV2.sol/NounsDAOExecutorV2.json'; export { NounsToken__factory as NounsTokenFactory } from '../typechain/factories/contracts/NounsToken__factory'; export { NounsAuctionHouse__factory as NounsAuctionHouseFactory } from '../typechain/factories/contracts/NounsAuctionHouse__factory'; export { NounsDescriptor__factory as NounsDescriptorFactory } from '../typechain/factories/contracts/NounsDescriptor__factory'; export { NounsSeeder__factory as NounsSeederFactory } from '../typechain/factories/contracts/NounsSeeder__factory'; -export { NounsDAOLogicV1__factory as NounsDaoLogicV1Factory } from '../typechain/factories/contracts/governance/NounsDAOLogicV1__factory'; -export { NounsDAOLogicV2__factory as NounsDaoLogicV2Factory } from '../typechain/factories/contracts/governance/NounsDAOLogicV2__factory'; -export { NounsDAOLogicV3__factory as NounsDaoLogicV3Factory } from '../typechain/factories/contracts/governance/NounsDAOLogicV3__factory'; -export { NounsDAOData__factory as NounsDaoDataFactory } from '../typechain/factories/contracts/governance/data/NounsDAOData__factory'; +export { NounsDAOLogicV4__factory as NounsDaoLogicFactory } from '../typechain/factories/contracts/governance/NounsDAOLogicV4__factory'; +export { NounsDAOData__factory as NounsDaoDataFactory } from '../typechain/factories/contracts/governance/data/NounsDAOData.sol/NounsDAOData__factory'; export { NounsDAOExecutorV2__factory as NounsDaoExecutorV2Factory } from '../typechain/factories/contracts/governance/NounsDAOExecutorV2__factory'; diff --git a/packages/nouns-contracts/tasks/create-proposal.ts b/packages/nouns-contracts/tasks/create-proposal.ts index 88239f4804..968ea95d70 100644 --- a/packages/nouns-contracts/tasks/create-proposal.ts +++ b/packages/nouns-contracts/tasks/create-proposal.ts @@ -9,14 +9,14 @@ task('create-proposal', 'Create a governance proposal') types.string, ) .setAction(async ({ nounsDaoProxy }, { ethers }) => { - const nounsDaoFactory = await ethers.getContractFactory('NounsDAOLogicV1'); + const nounsDaoFactory = await ethers.getContractFactory('NounsDAOLogicV4'); const nounsDao = nounsDaoFactory.attach(nounsDaoProxy); const [deployer] = await ethers.getSigners(); const oneETH = utils.parseEther('1'); const receipt = await ( - await nounsDao.propose( + await nounsDao['propose(address[],uint256[],string[],bytes[],string)']( [deployer.address], [oneETH], [''], diff --git a/packages/nouns-contracts/tasks/deploy-and-configure-short-times-daov1.ts b/packages/nouns-contracts/tasks/deploy-and-configure-short-times-daov1.ts deleted file mode 100644 index 5c6d7154ec..0000000000 --- a/packages/nouns-contracts/tasks/deploy-and-configure-short-times-daov1.ts +++ /dev/null @@ -1,106 +0,0 @@ -import { task, types } from 'hardhat/config'; -import { printContractsTable } from './utils'; - -task( - 'deploy-and-configure-short-times-daov1', - 'Deploy and configure all contracts with short gov times for testing', -) - .addFlag('startAuction', 'Start the first auction upon deployment completion') - .addFlag('autoDeploy', 'Deploy all contracts without user interaction') - .addFlag('updateConfigs', 'Write the deployed addresses to the SDK and subgraph configs') - .addOptionalParam('weth', 'The WETH contract address') - .addOptionalParam('noundersdao', 'The nounders DAO contract address') - .addOptionalParam( - 'auctionTimeBuffer', - 'The auction time buffer (seconds)', - 30 /* 30 seconds */, - types.int, - ) - .addOptionalParam( - 'auctionReservePrice', - 'The auction reserve price (wei)', - 1 /* 1 wei */, - types.int, - ) - .addOptionalParam( - 'auctionMinIncrementBidPercentage', - 'The auction min increment bid percentage (out of 100)', - 2 /* 2% */, - types.int, - ) - .addOptionalParam( - 'auctionDuration', - 'The auction duration (seconds)', - 60 * 2 /* 2 minutes */, - types.int, - ) - .addOptionalParam('timelockDelay', 'The timelock delay (seconds)', 60 /* 1 min */, types.int) - .addOptionalParam( - 'votingPeriod', - 'The voting period (blocks)', - 80 /* 20 min (15s blocks) */, - types.int, - ) - .addOptionalParam('votingDelay', 'The voting delay (blocks)', 1, types.int) - .addOptionalParam( - 'proposalThresholdBps', - 'The proposal threshold (basis points)', - 100 /* 1% */, - types.int, - ) - .addOptionalParam( - 'quorumVotesBps', - 'Votes required for quorum (basis points)', - 1_000 /* 10% */, - types.int, - ) - .setAction(async (args, { run }) => { - // Deploy the Nouns DAO contracts and return deployment information - const contracts = await run('deploy-short-times-daov1', args); - - // Verify the contracts on Etherscan - await run('verify-etherscan', { - contracts, - }); - - // Populate the on-chain art - await run('populate-descriptor', { - nftDescriptor: contracts.NFTDescriptorV2.address, - nounsDescriptor: contracts.NounsDescriptorV2.address, - }); - - // Transfer ownership of all contract except for the auction house. - // We must maintain ownership of the auction house to kick off the first auction. - const executorAddress = contracts.NounsDAOExecutor.address; - await contracts.NounsDescriptorV2.instance.transferOwnership(executorAddress); - await contracts.NounsToken.instance.transferOwnership(executorAddress); - await contracts.NounsAuctionHouseProxyAdmin.instance.transferOwnership(executorAddress); - console.log( - 'Transferred ownership of the descriptor, token, and proxy admin contracts to the executor.', - ); - - // Optionally kick off the first auction and transfer ownership of the auction house - // to the Nouns DAO executor. - if (args.startAuction) { - const auctionHouse = contracts.NounsAuctionHouse.instance.attach( - contracts.NounsAuctionHouseProxy.address, - ); - await auctionHouse.unpause({ - gasLimit: 1_000_000, - }); - await auctionHouse.transferOwnership(executorAddress); - console.log( - 'Started the first auction and transferred ownership of the auction house to the executor.', - ); - } - - // Optionally write the deployed addresses to the SDK and subgraph configs. - if (args.updateConfigs) { - await run('update-configs', { - contracts, - }); - } - - printContractsTable(contracts); - console.log('Deployment Complete.'); - }); diff --git a/packages/nouns-contracts/tasks/deploy-and-configure-short-times.ts b/packages/nouns-contracts/tasks/deploy-and-configure-short-times.ts deleted file mode 100644 index e731c51d9f..0000000000 --- a/packages/nouns-contracts/tasks/deploy-and-configure-short-times.ts +++ /dev/null @@ -1,108 +0,0 @@ -import { task, types } from 'hardhat/config'; -import { printContractsTable } from './utils'; - -task( - 'deploy-and-configure-short-times', - 'Deploy and configure all contracts with short gov times for testing', -) - .addFlag('startAuction', 'Start the first auction upon deployment completion') - .addFlag('autoDeploy', 'Deploy all contracts without user interaction') - .addFlag('updateConfigs', 'Write the deployed addresses to the SDK and subgraph configs') - .addOptionalParam('weth', 'The WETH contract address') - .addOptionalParam('noundersdao', 'The nounders DAO contract address') - .addOptionalParam( - 'auctionTimeBuffer', - 'The auction time buffer (seconds)', - 30 /* 30 seconds */, - types.int, - ) - .addOptionalParam( - 'auctionReservePrice', - 'The auction reserve price (wei)', - 1 /* 1 wei */, - types.int, - ) - .addOptionalParam( - 'auctionMinIncrementBidPercentage', - 'The auction min increment bid percentage (out of 100)', - 2 /* 2% */, - types.int, - ) - .addOptionalParam( - 'auctionDuration', - 'The auction duration (seconds)', - 60 * 2 /* 2 minutes */, - types.int, - ) - .addOptionalParam('timelockDelay', 'The timelock delay (seconds)', 60 /* 1 min */, types.int) - .addOptionalParam('votingPeriod', 'The voting period (blocks)', 25 /* 5 mins */, types.int) - .addOptionalParam('votingDelay', 'The voting delay (blocks)', 1, types.int) - .addOptionalParam( - 'proposalThresholdBps', - 'The proposal threshold (basis points)', - 100 /* 1% */, - types.int, - ) - .addOptionalParam( - 'minQuorumVotesBPS', - 'Min basis points input for dynamic quorum', - 1_000, - types.int, - ) // Default: 10% - .addOptionalParam( - 'maxQuorumVotesBPS', - 'Max basis points input for dynamic quorum', - 4_000, - types.int, - ) // Default: 40% - .addOptionalParam('quorumCoefficient', 'Dynamic quorum coefficient (float)', 1, types.float) - .setAction(async (args, { run }) => { - // Deploy the Nouns DAO contracts and return deployment information - const contracts = await run('deploy-short-times', args); - - // Verify the contracts on Etherscan - await run('verify-etherscan-daov2', { - contracts, - }); - - // Populate the on-chain art - await run('populate-descriptor', { - nftDescriptor: contracts.NFTDescriptorV2.address, - nounsDescriptor: contracts.NounsDescriptorV2.address, - }); - - // Transfer ownership of all contract except for the auction house. - // We must maintain ownership of the auction house to kick off the first auction. - const executorAddress = contracts.NounsDAOExecutor.address; - await contracts.NounsDescriptorV2.instance.transferOwnership(executorAddress); - await contracts.NounsToken.instance.transferOwnership(executorAddress); - await contracts.NounsAuctionHouseProxyAdmin.instance.transferOwnership(executorAddress); - console.log( - 'Transferred ownership of the descriptor, token, and proxy admin contracts to the executor.', - ); - - // Optionally kick off the first auction and transfer ownership of the auction house - // to the Nouns DAO executor. - if (args.startAuction) { - const auctionHouse = contracts.NounsAuctionHouse.instance.attach( - contracts.NounsAuctionHouseProxy.address, - ); - await auctionHouse.unpause({ - gasLimit: 1_000_000, - }); - await auctionHouse.transferOwnership(executorAddress); - console.log( - 'Started the first auction and transferred ownership of the auction house to the executor.', - ); - } - - // Optionally write the deployed addresses to the SDK and subgraph configs. - if (args.updateConfigs) { - await run('update-configs-daov2', { - contracts, - }); - } - - printContractsTable(contracts); - console.log('Deployment Complete.'); - }); diff --git a/packages/nouns-contracts/tasks/deploy-and-configure.ts b/packages/nouns-contracts/tasks/deploy-and-configure.ts deleted file mode 100644 index a2b7f56d5f..0000000000 --- a/packages/nouns-contracts/tasks/deploy-and-configure.ts +++ /dev/null @@ -1,76 +0,0 @@ -import { task, types } from 'hardhat/config'; -import { printContractsTable } from './utils'; - -task('deploy-and-configure', 'Deploy and configure all contracts') - .addFlag('startAuction', 'Start the first auction upon deployment completion') - .addFlag('autoDeploy', 'Deploy all contracts without user interaction') - .addFlag('updateConfigs', 'Write the deployed addresses to the SDK and subgraph configs') - .addOptionalParam('weth', 'The WETH contract address') - .addOptionalParam('noundersdao', 'The nounders DAO contract address') - .addOptionalParam( - 'auctionTimeBuffer', - 'The auction time buffer (seconds)', - 5 * 60 /* 5 minutes */, - types.int, - ) - .addOptionalParam('auctionReservePrice', 'The auction reserve price (wei)') - .addOptionalParam( - 'auctionMinIncrementBidPercentage', - 'The auction min increment bid percentage (out of 100)', - ) - .addOptionalParam('auctionDuration', 'The auction duration (seconds)') - .addOptionalParam('timelockDelay', 'The timelock delay (seconds)') - .addOptionalParam('votingPeriod', 'The voting period (blocks)') - .addOptionalParam('votingDelay', 'The voting delay (blocks)') - .addOptionalParam('proposalThresholdBps', 'The proposal threshold (basis points)') - .addOptionalParam('quorumVotesBps', 'Votes required for quorum (basis points)') - .setAction(async (args, { run }) => { - // Deploy the Nouns DAO contracts and return deployment information - const contracts = await run('deploy', args); - - // Verify the contracts on Etherscan - await run('verify-etherscan', { - contracts, - }); - - // Populate the on-chain art - await run('populate-descriptor', { - nftDescriptor: contracts.NFTDescriptorV2.address, - nounsDescriptor: contracts.NounsDescriptorV2.address, - }); - - // Transfer ownership of all contract except for the auction house. - // We must maintain ownership of the auction house to kick off the first auction. - const executorAddress = contracts.NounsDAOExecutor.address; - await contracts.NounsDescriptorV2.instance.transferOwnership(executorAddress); - await contracts.NounsToken.instance.transferOwnership(executorAddress); - await contracts.NounsAuctionHouseProxyAdmin.instance.transferOwnership(executorAddress); - console.log( - 'Transferred ownership of the descriptor, token, and proxy admin contracts to the executor.', - ); - - // Optionally kick off the first auction and transfer ownership of the auction house - // to the Nouns DAO executor. - if (args.startAuction) { - const auctionHouse = contracts.NounsAuctionHouse.instance.attach( - contracts.NounsAuctionHouseProxy.address, - ); - await auctionHouse.unpause({ - gasLimit: 1_000_000, - }); - await auctionHouse.transferOwnership(executorAddress); - console.log( - 'Started the first auction and transferred ownership of the auction house to the executor.', - ); - } - - // Optionally write the deployed addresses to the SDK and subgraph configs. - if (args.updateConfigs) { - await run('update-configs', { - contracts, - }); - } - - printContractsTable(contracts); - console.log('Deployment Complete.'); - }); diff --git a/packages/nouns-contracts/tasks/deploy-ci.ts b/packages/nouns-contracts/tasks/deploy-ci.ts deleted file mode 100644 index c0aeb83b7b..0000000000 --- a/packages/nouns-contracts/tasks/deploy-ci.ts +++ /dev/null @@ -1,37 +0,0 @@ -import fs from 'fs'; -import { task } from 'hardhat/config'; - -task('deploy-ci', 'Deploy contracts (automated by CI)') - .addOptionalParam('noundersdao', 'The nounders DAO contract address') - .addOptionalParam( - 'weth', - 'The WETH contract address', - '0xc778417e063141139fce010982780140aa0cd5ab', - ) - .setAction(async ({ noundersdao, weth }, { ethers, run }) => { - const [deployer] = await ethers.getSigners(); - const contracts = await run('deploy', { - weth, - noundersDAO: noundersdao || deployer.address, - }); - - if (!fs.existsSync('logs')) { - fs.mkdirSync('logs'); - } - fs.writeFileSync( - 'logs/deploy.json', - JSON.stringify({ - contractAddresses: { - NFTDescriptor: contracts.NFTDescriptor.address, - NounsDescriptor: contracts.NounsDescriptor.address, - NounsSeeder: contracts.NounsSeeder.address, - NounsToken: contracts.NounsToken.address, - }, - gitHub: { - // Get the commit sha when running in CI - sha: process.env.GITHUB_SHA, - }, - }), - { flag: 'w' }, - ); - }); diff --git a/packages/nouns-contracts/tasks/deploy-descriptor-v2.ts b/packages/nouns-contracts/tasks/deploy-descriptor-v2.ts index 953cd5d7c1..b93bfb2313 100644 --- a/packages/nouns-contracts/tasks/deploy-descriptor-v2.ts +++ b/packages/nouns-contracts/tasks/deploy-descriptor-v2.ts @@ -1,5 +1,5 @@ import { task } from 'hardhat/config'; -import { ContractName, DeployedContract } from './types'; +import { ContractNamesDAOV3, DeployedContract } from './types'; import { printContractsTable } from './utils'; async function delay(seconds: number) { @@ -12,8 +12,8 @@ task('deploy-descriptor-v2', 'Deploy NounsDescriptorV2 & populate it with art') 'The address of the NounsDAOExecutor that should be the owner of the descriptor.', ) .setAction(async ({ daoExecutor }, { ethers, run, network }) => { - const contracts: Record = {} as Record< - ContractName, + const contracts: Record = {} as Record< + ContractNamesDAOV3, DeployedContract >; const [deployer] = await ethers.getSigners(); diff --git a/packages/nouns-contracts/tasks/deploy-local-dao-v3.ts b/packages/nouns-contracts/tasks/deploy-local-dao-v3.ts index 588c8e4d67..90f5843e94 100644 --- a/packages/nouns-contracts/tasks/deploy-local-dao-v3.ts +++ b/packages/nouns-contracts/tasks/deploy-local-dao-v3.ts @@ -4,31 +4,9 @@ import { default as NounsDAOExecutorV2ABI } from '../abi/contracts/governance/No import { task, types } from 'hardhat/config'; import { Interface, parseUnits } from 'ethers/lib/utils'; import { Contract as EthersContract } from 'ethers'; -import { ContractName } from './types'; +import { ContractNamesDAOV3 } from './types'; -type LocalContractName = - | Exclude< - ContractName, - 'NounsDAOLogicV1' | 'NounsDAOProxy' | 'NounsDAOLogicV2' | 'NounsDAOExecutor' - > - | 'NounsDAOLogicV3' - | 'NounsDAOProxyV3' - | 'NounsDAOV3Admin' - | 'NounsDAOV3DynamicQuorum' - | 'NounsDAOV3Proposals' - | 'NounsDAOV3Votes' - | 'NounsDAOV3Fork' - | 'NounsDAOForkEscrow' - | 'ForkDAODeployer' - | 'NounsTokenFork' - | 'NounsAuctionHouseFork' - | 'NounsDAOLogicV1Fork' - | 'NounsDAOExecutorV2' - | 'NounsDAOExecutorProxy' - | 'WETH' - | 'Multicall2' - | 'NounsDAOData' - | 'NounsDAODataProxy'; +type LocalContractName = ContractNamesDAOV3 | 'WETH' | 'Multicall2'; interface Contract { args?: (string | number | (() => string | undefined))[]; @@ -156,18 +134,18 @@ task('deploy-local-dao-v3', 'Deploy contracts to hardhat') ]), ], }, - NounsDAOV3DynamicQuorum: {}, + NounsDAODynamicQuorum: {}, NounsDAOV3Admin: {}, - NounsDAOV3Proposals: {}, - NounsDAOV3Votes: {}, - NounsDAOV3Fork: {}, - NounsDAOLogicV3: { + NounsDAOProposals: {}, + NounsDAOVotes: {}, + NounsDAOFork: {}, + NounsDAOLogicV4: { libraries: () => ({ NounsDAOV3Admin: contracts.NounsDAOV3Admin.instance?.address as string, - NounsDAOV3DynamicQuorum: contracts.NounsDAOV3DynamicQuorum.instance?.address as string, - NounsDAOV3Proposals: contracts.NounsDAOV3Proposals.instance?.address as string, - NounsDAOV3Votes: contracts.NounsDAOV3Votes.instance?.address as string, - NounsDAOV3Fork: contracts.NounsDAOV3Fork.instance?.address as string, + NounsDAODynamicQuorum: contracts.NounsDAODynamicQuorum.instance?.address as string, + NounsDAOProposals: contracts.NounsDAOProposals.instance?.address as string, + NounsDAOVotes: contracts.NounsDAOVotes.instance?.address as string, + NounsDAOFork: contracts.NounsDAOFork.instance?.address as string, }), waitForConfirmation: true, }, @@ -212,7 +190,7 @@ task('deploy-local-dao-v3', 'Deploy contracts to hardhat') () => contracts.ForkDAODeployer.instance?.address, // forkDAODeployer args.noundersdao || deployer.address, // vetoer () => contracts.NounsDAOExecutorProxy.instance?.address, // admin - () => contracts.NounsDAOLogicV3.instance?.address, // implementation + () => contracts.NounsDAOLogicV4.instance?.address, // implementation { votingPeriod: args.votingPeriod, votingDelay: args.votingDelay, diff --git a/packages/nouns-contracts/tasks/deploy-local.ts b/packages/nouns-contracts/tasks/deploy-local.ts deleted file mode 100644 index e5d0192d11..0000000000 --- a/packages/nouns-contracts/tasks/deploy-local.ts +++ /dev/null @@ -1,168 +0,0 @@ -import { default as NounsAuctionHouseABI } from '../abi/contracts/NounsAuctionHouse.sol/NounsAuctionHouse.json'; -import { task, types } from 'hardhat/config'; -import { Interface, parseUnits } from 'ethers/lib/utils'; -import { Contract as EthersContract } from 'ethers'; -import { ContractName } from './types'; - -type LocalContractName = - | Exclude - | 'NounsDAOLogicV2' - | 'NounsDAOProxyV2' - | 'WETH' - | 'Multicall2'; - -interface Contract { - args?: (string | number | (() => string | undefined))[]; - instance?: EthersContract; - libraries?: () => Record; - waitForConfirmation?: boolean; -} - -task('deploy-local', 'Deploy contracts to hardhat') - .addOptionalParam('noundersdao', 'The nounders DAO contract address') - .addOptionalParam('auctionTimeBuffer', 'The auction time buffer (seconds)', 30, types.int) // Default: 30 seconds - .addOptionalParam('auctionReservePrice', 'The auction reserve price (wei)', 1, types.int) // Default: 1 wei - .addOptionalParam( - 'auctionMinIncrementBidPercentage', - 'The auction min increment bid percentage (out of 100)', // Default: 5% - 5, - types.int, - ) - .addOptionalParam('auctionDuration', 'The auction duration (seconds)', 60 * 2, types.int) // Default: 2 minutes - .addOptionalParam('timelockDelay', 'The timelock delay (seconds)', 60 * 60 * 24 * 2, types.int) // Default: 2 days - .addOptionalParam('votingPeriod', 'The voting period (blocks)', 4 * 60 * 24 * 3, types.int) // Default: 3 days - .addOptionalParam('votingDelay', 'The voting delay (blocks)', 1, types.int) // Default: 1 block - .addOptionalParam('proposalThresholdBps', 'The proposal threshold (basis points)', 500, types.int) // Default: 5% - .addOptionalParam( - 'minQuorumVotesBPS', - 'Min basis points input for dynamic quorum', - 1_000, - types.int, - ) // Default: 10% - .addOptionalParam( - 'maxQuorumVotesBPS', - 'Max basis points input for dynamic quorum', - 4_000, - types.int, - ) // Default: 40% - .addOptionalParam('quorumCoefficient', 'Dynamic quorum coefficient (float)', 1, types.float) - .setAction(async (args, { ethers }) => { - const network = await ethers.provider.getNetwork(); - if (network.chainId !== 31337) { - console.log(`Invalid chain id. Expected 31337. Got: ${network.chainId}.`); - return; - } - - const proxyRegistryAddress = '0xa5409ec958c83c3f309868babaca7c86dcb077c1'; - - const NOUNS_ART_NONCE_OFFSET = 5; - const AUCTION_HOUSE_PROXY_NONCE_OFFSET = 10; - const GOVERNOR_N_DELEGATOR_NONCE_OFFSET = 13; - - const [deployer] = await ethers.getSigners(); - const nonce = await deployer.getTransactionCount(); - const expectedNounsArtAddress = ethers.utils.getContractAddress({ - from: deployer.address, - nonce: nonce + NOUNS_ART_NONCE_OFFSET, - }); - const expectedNounsDAOProxyAddress = ethers.utils.getContractAddress({ - from: deployer.address, - nonce: nonce + GOVERNOR_N_DELEGATOR_NONCE_OFFSET, - }); - const expectedAuctionHouseProxyAddress = ethers.utils.getContractAddress({ - from: deployer.address, - nonce: nonce + AUCTION_HOUSE_PROXY_NONCE_OFFSET, - }); - const contracts: Record = { - WETH: {}, - NFTDescriptorV2: {}, - SVGRenderer: {}, - NounsDescriptorV2: { - args: [expectedNounsArtAddress, () => contracts.SVGRenderer.instance?.address], - libraries: () => ({ - NFTDescriptorV2: contracts.NFTDescriptorV2.instance?.address as string, - }), - }, - Inflator: {}, - NounsArt: { - args: [ - () => contracts.NounsDescriptorV2.instance?.address, - () => contracts.Inflator.instance?.address, - ], - }, - NounsSeeder: {}, - NounsToken: { - args: [ - args.noundersdao || deployer.address, - expectedAuctionHouseProxyAddress, - () => contracts.NounsDescriptorV2.instance?.address, - () => contracts.NounsSeeder.instance?.address, - proxyRegistryAddress, - ], - }, - NounsAuctionHouse: { - waitForConfirmation: true, - }, - NounsAuctionHouseProxyAdmin: {}, - NounsAuctionHouseProxy: { - args: [ - () => contracts.NounsAuctionHouse.instance?.address, - () => contracts.NounsAuctionHouseProxyAdmin.instance?.address, - () => - new Interface(NounsAuctionHouseABI).encodeFunctionData('initialize', [ - contracts.NounsToken.instance?.address, - contracts.WETH.instance?.address, - args.auctionTimeBuffer, - args.auctionReservePrice, - args.auctionMinIncrementBidPercentage, - args.auctionDuration, - ]), - ], - }, - NounsDAOExecutor: { - args: [expectedNounsDAOProxyAddress, args.timelockDelay], - }, - NounsDAOLogicV2: { - waitForConfirmation: true, - }, - NounsDAOProxyV2: { - args: [ - () => contracts.NounsDAOExecutor.instance?.address, - () => contracts.NounsToken.instance?.address, - args.noundersdao || deployer.address, - () => contracts.NounsDAOExecutor.instance?.address, - () => contracts.NounsDAOLogicV2.instance?.address, - args.votingPeriod, - args.votingDelay, - args.proposalThresholdBps, - { - minQuorumVotesBPS: args.minQuorumVotesBPS, - maxQuorumVotesBPS: args.maxQuorumVotesBPS, - quorumCoefficient: parseUnits(args.quorumCoefficient.toString(), 6), - }, - ], - waitForConfirmation: true, - }, - Multicall2: {}, - }; - - for (const [name, contract] of Object.entries(contracts)) { - const factory = await ethers.getContractFactory(name, { - libraries: contract?.libraries?.(), - }); - - const deployedContract = await factory.deploy( - ...(contract.args?.map(a => (typeof a === 'function' ? a() : a)) ?? []), - ); - - if (contract.waitForConfirmation) { - await deployedContract.deployed(); - } - - contracts[name as LocalContractName].instance = deployedContract; - - console.log(`${name} contract deployed to ${deployedContract.address}`); - } - - return contracts; - }); diff --git a/packages/nouns-contracts/tasks/deploy-short-times-dao-v3.ts b/packages/nouns-contracts/tasks/deploy-short-times-dao-v3.ts index f0fcdb5753..93db50839f 100644 --- a/packages/nouns-contracts/tasks/deploy-short-times-dao-v3.ts +++ b/packages/nouns-contracts/tasks/deploy-short-times-dao-v3.ts @@ -187,18 +187,18 @@ task('deploy-short-times-dao-v3', 'Deploy all Nouns contracts with short gov tim } }, }, - NounsDAOV3DynamicQuorum: {}, - NounsDAOV3Admin: {}, - NounsDAOV3Proposals: {}, - NounsDAOV3Votes: {}, - NounsDAOV3Fork: {}, - NounsDAOLogicV3: { + NounsDAODynamicQuorum: {}, + NounsDAOAdmin: {}, + NounsDAOProposals: {}, + NounsDAOVotes: {}, + NounsDAOFork: {}, + NounsDAOLogicV4: { libraries: () => ({ - NounsDAOV3Admin: deployment.NounsDAOV3Admin.address, - NounsDAOV3DynamicQuorum: deployment.NounsDAOV3DynamicQuorum.address, - NounsDAOV3Proposals: deployment.NounsDAOV3Proposals.address, - NounsDAOV3Votes: deployment.NounsDAOV3Votes.address, - NounsDAOV3Fork: deployment.NounsDAOV3Fork.address, + NounsDAOAdmin: deployment.NounsDAOAdmin.address, + NounsDAODynamicQuorum: deployment.NounsDAODynamicQuorum.address, + NounsDAOProposals: deployment.NounsDAOProposals.address, + NounsDAOVotes: deployment.NounsDAOVotes.address, + NounsDAOFork: deployment.NounsDAOFork.address, }), waitForConfirmation: true, }, @@ -242,7 +242,7 @@ task('deploy-short-times-dao-v3', 'Deploy all Nouns contracts with short gov tim () => deployment.ForkDAODeployer.address, // forkDAODeployer args.noundersdao || deployer.address, // vetoer () => deployment.NounsDAOExecutorProxy.address, // admin - () => deployment.NounsDAOLogicV3.address, // implementation + () => deployment.NounsDAOLogicV4.address, // implementation { votingPeriod: args.votingPeriod, votingDelay: args.votingDelay, @@ -287,9 +287,22 @@ task('deploy-short-times-dao-v3', 'Deploy all Nouns contracts with short gov tim }; for (const [name, contract] of Object.entries(contracts)) { - let gasPrice = await ethers.provider.getGasPrice(); + let gasOptions; + let feeData = await ethers.provider.getFeeData(); + if (args.autoDeploy) { + gasOptions = { + maxFeePerGas: feeData.maxFeePerGas, + maxPriorityFeePerGas: feeData.maxPriorityFeePerGas, + }; + } else { + gasOptions = { + gasPrice: feeData.gasPrice!, + }; + } if (!args.autoDeploy) { - const gasInGwei = Math.round(Number(ethers.utils.formatUnits(gasPrice, 'gwei'))); + const gasInGwei = Math.round( + Number(ethers.utils.formatUnits(gasOptions.gasPrice!, 'gwei')), + ); promptjs.start(); @@ -305,7 +318,7 @@ task('deploy-short-times-dao-v3', 'Deploy all Nouns contracts with short gov tim }, }, ]); - gasPrice = ethers.utils.parseUnits(result.gasPrice.toString(), 'gwei'); + gasOptions.gasPrice = ethers.utils.parseUnits(result.gasPrice.toString(), 'gwei'); } let nameForFactory: string; @@ -313,7 +326,7 @@ task('deploy-short-times-dao-v3', 'Deploy all Nouns contracts with short gov tim case 'NounsDAOExecutorV2': nameForFactory = 'NounsDAOExecutorV2Test'; break; - case 'NounsDAOLogicV3': + case 'NounsDAOLogicV4': nameForFactory = 'NounsDAOLogicV3Harness'; break; default: @@ -328,21 +341,20 @@ task('deploy-short-times-dao-v3', 'Deploy all Nouns contracts with short gov tim const deploymentGas = await factory.signer.estimateGas( factory.getDeployTransaction( ...(contract.args?.map(a => (typeof a === 'function' ? a() : a)) ?? []), - { - gasPrice, - }, + gasOptions, ), ); - const deploymentCost = deploymentGas.mul(gasPrice); - - console.log( - `Estimated cost to deploy ${name}: ${ethers.utils.formatUnits( - deploymentCost, - 'ether', - )} ETH`, - ); if (!args.autoDeploy) { + const deploymentCost = deploymentGas.mul(gasOptions.gasPrice!); + + console.log( + `Estimated cost to deploy ${name}: ${ethers.utils.formatUnits( + deploymentCost, + 'ether', + )} ETH`, + ); + const result = await promptjs.get([ { properties: { @@ -367,9 +379,7 @@ task('deploy-short-times-dao-v3', 'Deploy all Nouns contracts with short gov tim const deployedContract = await factory.deploy( ...(contract.args?.map(a => (typeof a === 'function' ? a() : a)) ?? []), - { - gasPrice, - }, + gasOptions, ); if (contract.waitForConfirmation) { diff --git a/packages/nouns-contracts/tasks/deploy-short-times-daov1.ts b/packages/nouns-contracts/tasks/deploy-short-times-daov1.ts deleted file mode 100644 index 9bde8df632..0000000000 --- a/packages/nouns-contracts/tasks/deploy-short-times-daov1.ts +++ /dev/null @@ -1,301 +0,0 @@ -import { default as NounsAuctionHouseABI } from '../abi/contracts/NounsAuctionHouse.sol/NounsAuctionHouse.json'; -import { ChainId, ContractDeployment, ContractName, DeployedContract } from './types'; -import { Interface } from 'ethers/lib/utils'; -import { task, types } from 'hardhat/config'; -import { constants } from 'ethers'; -import promptjs from 'prompt'; - -promptjs.colors = false; -promptjs.message = '> '; -promptjs.delimiter = ''; - -const proxyRegistries: Record = { - [ChainId.Mainnet]: '0xa5409ec958c83c3f309868babaca7c86dcb077c1', -}; -const wethContracts: Record = { - [ChainId.Mainnet]: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', - [ChainId.Ropsten]: '0xc778417e063141139fce010982780140aa0cd5ab', - [ChainId.Kovan]: '0xd0a1e359811322d97991e03f863a0c30c2cf029c', - [ChainId.Goerli]: '0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6', -}; - -const NOUNS_ART_NONCE_OFFSET = 4; -const AUCTION_HOUSE_PROXY_NONCE_OFFSET = 9; -const GOVERNOR_N_DELEGATOR_NONCE_OFFSET = 12; - -task('deploy-short-times-daov1', 'Deploy all Nouns contracts with short gov times for testing') - .addFlag('autoDeploy', 'Deploy all contracts without user interaction') - .addOptionalParam('weth', 'The WETH contract address', undefined, types.string) - .addOptionalParam('noundersdao', 'The nounders DAO contract address', undefined, types.string) - .addOptionalParam( - 'auctionTimeBuffer', - 'The auction time buffer (seconds)', - 30 /* 30 seconds */, - types.int, - ) - .addOptionalParam( - 'auctionReservePrice', - 'The auction reserve price (wei)', - 1 /* 1 wei */, - types.int, - ) - .addOptionalParam( - 'auctionMinIncrementBidPercentage', - 'The auction min increment bid percentage (out of 100)', - 2 /* 2% */, - types.int, - ) - .addOptionalParam( - 'auctionDuration', - 'The auction duration (seconds)', - 60 * 2 /* 2 minutes */, - types.int, - ) - .addOptionalParam('timelockDelay', 'The timelock delay (seconds)', 60 /* 1 min */, types.int) - .addOptionalParam( - 'votingPeriod', - 'The voting period (blocks)', - 80 /* 20 min (15s blocks) */, - types.int, - ) - .addOptionalParam('votingDelay', 'The voting delay (blocks)', 1, types.int) - .addOptionalParam( - 'proposalThresholdBps', - 'The proposal threshold (basis points)', - 100 /* 1% */, - types.int, - ) - .addOptionalParam( - 'quorumVotesBps', - 'Votes required for quorum (basis points)', - 1_000 /* 10% */, - types.int, - ) - .setAction(async (args, { ethers }) => { - const network = await ethers.provider.getNetwork(); - const [deployer] = await ethers.getSigners(); - - // prettier-ignore - const proxyRegistryAddress = proxyRegistries[network.chainId] ?? constants.AddressZero; - - if (!args.noundersdao) { - console.log( - `Nounders DAO address not provided. Setting to deployer (${deployer.address})...`, - ); - args.noundersdao = deployer.address; - } - if (!args.weth) { - const deployedWETHContract = wethContracts[network.chainId]; - if (!deployedWETHContract) { - throw new Error( - `Can not auto-detect WETH contract on chain ${network.name}. Provide it with the --weth arg.`, - ); - } - args.weth = deployedWETHContract; - } - - const nonce = await deployer.getTransactionCount(); - const expectedNounsArtAddress = ethers.utils.getContractAddress({ - from: deployer.address, - nonce: nonce + NOUNS_ART_NONCE_OFFSET, - }); - const expectedAuctionHouseProxyAddress = ethers.utils.getContractAddress({ - from: deployer.address, - nonce: nonce + AUCTION_HOUSE_PROXY_NONCE_OFFSET, - }); - const expectedNounsDAOProxyAddress = ethers.utils.getContractAddress({ - from: deployer.address, - nonce: nonce + GOVERNOR_N_DELEGATOR_NONCE_OFFSET, - }); - const deployment: Record = {} as Record< - ContractName, - DeployedContract - >; - const contracts: Record = { - NFTDescriptorV2: {}, - SVGRenderer: {}, - NounsDescriptorV2: { - args: [expectedNounsArtAddress, () => deployment.SVGRenderer.address], - libraries: () => ({ - NFTDescriptorV2: deployment.NFTDescriptorV2.address, - }), - }, - Inflator: {}, - NounsArt: { - args: [() => deployment.NounsDescriptorV2.address, () => deployment.Inflator.address], - }, - NounsSeeder: {}, - NounsToken: { - args: [ - args.noundersdao, - expectedAuctionHouseProxyAddress, - () => deployment.NounsDescriptorV2.address, - () => deployment.NounsSeeder.address, - proxyRegistryAddress, - ], - }, - NounsAuctionHouse: { - waitForConfirmation: true, - }, - NounsAuctionHouseProxyAdmin: {}, - NounsAuctionHouseProxy: { - args: [ - () => deployment.NounsAuctionHouse.address, - () => deployment.NounsAuctionHouseProxyAdmin.address, - () => - new Interface(NounsAuctionHouseABI).encodeFunctionData('initialize', [ - deployment.NounsToken.address, - args.weth, - args.auctionTimeBuffer, - args.auctionReservePrice, - args.auctionMinIncrementBidPercentage, - args.auctionDuration, - ]), - ], - waitForConfirmation: true, - validateDeployment: () => { - const expected = expectedAuctionHouseProxyAddress.toLowerCase(); - const actual = deployment.NounsAuctionHouseProxy.address.toLowerCase(); - if (expected !== actual) { - throw new Error( - `Unexpected auction house proxy address. Expected: ${expected}. Actual: ${actual}.`, - ); - } - }, - }, - NounsDAOExecutor: { - args: [expectedNounsDAOProxyAddress, args.timelockDelay], - }, - NounsDAOLogicV1: { - waitForConfirmation: true, - }, - NounsDAOProxy: { - args: [ - () => deployment.NounsDAOExecutor.address, - () => deployment.NounsToken.address, - args.noundersdao, - () => deployment.NounsDAOExecutor.address, - () => deployment.NounsDAOLogicV1.address, - args.votingPeriod, - args.votingDelay, - args.proposalThresholdBps, - args.quorumVotesBps, - ], - waitForConfirmation: true, - validateDeployment: () => { - const expected = expectedNounsDAOProxyAddress.toLowerCase(); - const actual = deployment.NounsDAOProxy.address.toLowerCase(); - if (expected !== actual) { - throw new Error( - `Unexpected Nouns DAO proxy address. Expected: ${expected}. Actual: ${actual}.`, - ); - } - }, - }, - }; - - for (const [name, contract] of Object.entries(contracts)) { - let gasPrice = await ethers.provider.getGasPrice(); - if (!args.autoDeploy) { - const gasInGwei = Math.round(Number(ethers.utils.formatUnits(gasPrice, 'gwei'))); - - promptjs.start(); - - const result = await promptjs.get([ - { - properties: { - gasPrice: { - type: 'integer', - required: true, - description: 'Enter a gas price (gwei)', - default: gasInGwei, - }, - }, - }, - ]); - gasPrice = ethers.utils.parseUnits(result.gasPrice.toString(), 'gwei'); - } - - let nameForFactory: string; - switch (name) { - case 'NounsDAOExecutor': - nameForFactory = 'NounsDAOExecutorTest'; - break; - case 'NounsDAOLogicV1': - nameForFactory = 'NounsDAOLogicV1Harness'; - break; - default: - nameForFactory = name; - break; - } - - const factory = await ethers.getContractFactory(nameForFactory, { - libraries: contract?.libraries?.(), - }); - - const deploymentGas = await factory.signer.estimateGas( - factory.getDeployTransaction( - ...(contract.args?.map(a => (typeof a === 'function' ? a() : a)) ?? []), - { - gasPrice, - }, - ), - ); - const deploymentCost = deploymentGas.mul(gasPrice); - - console.log( - `Estimated cost to deploy ${name}: ${ethers.utils.formatUnits( - deploymentCost, - 'ether', - )} ETH`, - ); - - if (!args.autoDeploy) { - const result = await promptjs.get([ - { - properties: { - confirm: { - pattern: /^(DEPLOY|SKIP|EXIT)$/, - description: - 'Type "DEPLOY" to confirm, "SKIP" to skip this contract, or "EXIT" to exit.', - }, - }, - }, - ]); - if (result.operation === 'SKIP') { - console.log(`Skipping ${name} deployment...`); - continue; - } - if (result.operation === 'EXIT') { - console.log('Exiting...'); - return; - } - } - console.log(`Deploying ${name}...`); - - const deployedContract = await factory.deploy( - ...(contract.args?.map(a => (typeof a === 'function' ? a() : a)) ?? []), - { - gasPrice, - }, - ); - - if (contract.waitForConfirmation) { - await deployedContract.deployed(); - } - - deployment[name as ContractName] = { - name: nameForFactory, - instance: deployedContract, - address: deployedContract.address, - constructorArguments: contract.args?.map(a => (typeof a === 'function' ? a() : a)) ?? [], - libraries: contract?.libraries?.() ?? {}, - }; - - contract.validateDeployment?.(); - - console.log(`${name} contract deployed to ${deployedContract.address}`); - } - - return deployment; - }); diff --git a/packages/nouns-contracts/tasks/deploy-short-times.ts b/packages/nouns-contracts/tasks/deploy-short-times.ts deleted file mode 100644 index 610baa3ebe..0000000000 --- a/packages/nouns-contracts/tasks/deploy-short-times.ts +++ /dev/null @@ -1,315 +0,0 @@ -import { default as NounsAuctionHouseABI } from '../abi/contracts/NounsAuctionHouse.sol/NounsAuctionHouse.json'; -import { ChainId, ContractDeployment, ContractNamesDAOV2, DeployedContract } from './types'; -import { Interface, parseUnits } from 'ethers/lib/utils'; -import { task, types } from 'hardhat/config'; -import { constants } from 'ethers'; -import promptjs from 'prompt'; - -promptjs.colors = false; -promptjs.message = '> '; -promptjs.delimiter = ''; - -const proxyRegistries: Record = { - [ChainId.Mainnet]: '0xa5409ec958c83c3f309868babaca7c86dcb077c1', - [ChainId.Goerli]: '0x5d44754DE92363d5746485F31280E4c0c54c855c', // ProxyRegistryMock - [ChainId.Sepolia]: '0x152E981d511F8c0865354A71E1cb84d0FB318470', // ProxyRegistryMock -}; -const wethContracts: Record = { - [ChainId.Mainnet]: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', - [ChainId.Ropsten]: '0xc778417e063141139fce010982780140aa0cd5ab', - [ChainId.Kovan]: '0xd0a1e359811322d97991e03f863a0c30c2cf029c', - [ChainId.Goerli]: '0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6', - [ChainId.Sepolia]: '0xfFf9976782d46CC05630D1f6eBAb18b2324d6B14', -}; - -const NOUNS_ART_NONCE_OFFSET = 4; -const AUCTION_HOUSE_PROXY_NONCE_OFFSET = 9; -const GOVERNOR_N_DELEGATOR_NONCE_OFFSET = 12; - -task('deploy-short-times', 'Deploy all Nouns contracts with short gov times for testing') - .addFlag('autoDeploy', 'Deploy all contracts without user interaction') - .addOptionalParam('weth', 'The WETH contract address', undefined, types.string) - .addOptionalParam('noundersdao', 'The nounders DAO contract address', undefined, types.string) - .addOptionalParam( - 'auctionTimeBuffer', - 'The auction time buffer (seconds)', - 30 /* 30 seconds */, - types.int, - ) - .addOptionalParam( - 'auctionReservePrice', - 'The auction reserve price (wei)', - 1 /* 1 wei */, - types.int, - ) - .addOptionalParam( - 'auctionMinIncrementBidPercentage', - 'The auction min increment bid percentage (out of 100)', - 2 /* 2% */, - types.int, - ) - .addOptionalParam( - 'auctionDuration', - 'The auction duration (seconds)', - 60 * 2 /* 2 minutes */, - types.int, - ) - .addOptionalParam('timelockDelay', 'The timelock delay (seconds)', 60 /* 1 min */, types.int) - .addOptionalParam( - 'votingPeriod', - 'The voting period (blocks)', - 80 /* 20 min (15s blocks) */, - types.int, - ) - .addOptionalParam('votingDelay', 'The voting delay (blocks)', 1, types.int) - .addOptionalParam( - 'proposalThresholdBps', - 'The proposal threshold (basis points)', - 100 /* 1% */, - types.int, - ) - .addOptionalParam( - 'minQuorumVotesBPS', - 'Min basis points input for dynamic quorum', - 1_000, - types.int, - ) // Default: 10% - .addOptionalParam( - 'maxQuorumVotesBPS', - 'Max basis points input for dynamic quorum', - 4_000, - types.int, - ) // Default: 40% - .addOptionalParam('quorumCoefficient', 'Dynamic quorum coefficient (float)', 1, types.float) - .setAction(async (args, { ethers }) => { - const network = await ethers.provider.getNetwork(); - const [deployer] = await ethers.getSigners(); - - // prettier-ignore - const proxyRegistryAddress = proxyRegistries[network.chainId] ?? constants.AddressZero; - - if (!args.noundersdao) { - console.log( - `Nounders DAO address not provided. Setting to deployer (${deployer.address})...`, - ); - args.noundersdao = deployer.address; - } - if (!args.weth) { - const deployedWETHContract = wethContracts[network.chainId]; - if (!deployedWETHContract) { - throw new Error( - `Can not auto-detect WETH contract on chain ${network.name}. Provide it with the --weth arg.`, - ); - } - args.weth = deployedWETHContract; - } - - const nonce = await deployer.getTransactionCount(); - const expectedNounsArtAddress = ethers.utils.getContractAddress({ - from: deployer.address, - nonce: nonce + NOUNS_ART_NONCE_OFFSET, - }); - const expectedAuctionHouseProxyAddress = ethers.utils.getContractAddress({ - from: deployer.address, - nonce: nonce + AUCTION_HOUSE_PROXY_NONCE_OFFSET, - }); - const expectedNounsDAOProxyAddress = ethers.utils.getContractAddress({ - from: deployer.address, - nonce: nonce + GOVERNOR_N_DELEGATOR_NONCE_OFFSET, - }); - const deployment: Record = {} as Record< - ContractNamesDAOV2, - DeployedContract - >; - const contracts: Record = { - NFTDescriptorV2: {}, - SVGRenderer: {}, - NounsDescriptorV2: { - args: [expectedNounsArtAddress, () => deployment.SVGRenderer.address], - libraries: () => ({ - NFTDescriptorV2: deployment.NFTDescriptorV2.address, - }), - }, - Inflator: {}, - NounsArt: { - args: [() => deployment.NounsDescriptorV2.address, () => deployment.Inflator.address], - }, - NounsSeeder: {}, - NounsToken: { - args: [ - args.noundersdao, - expectedAuctionHouseProxyAddress, - () => deployment.NounsDescriptorV2.address, - () => deployment.NounsSeeder.address, - proxyRegistryAddress, - ], - }, - NounsAuctionHouse: { - waitForConfirmation: true, - }, - NounsAuctionHouseProxyAdmin: {}, - NounsAuctionHouseProxy: { - args: [ - () => deployment.NounsAuctionHouse.address, - () => deployment.NounsAuctionHouseProxyAdmin.address, - () => - new Interface(NounsAuctionHouseABI).encodeFunctionData('initialize', [ - deployment.NounsToken.address, - args.weth, - args.auctionTimeBuffer, - args.auctionReservePrice, - args.auctionMinIncrementBidPercentage, - args.auctionDuration, - ]), - ], - waitForConfirmation: true, - validateDeployment: () => { - const expected = expectedAuctionHouseProxyAddress.toLowerCase(); - const actual = deployment.NounsAuctionHouseProxy.address.toLowerCase(); - if (expected !== actual) { - throw new Error( - `Unexpected auction house proxy address. Expected: ${expected}. Actual: ${actual}.`, - ); - } - }, - }, - NounsDAOExecutor: { - args: [expectedNounsDAOProxyAddress, args.timelockDelay], - }, - NounsDAOLogicV2: { - waitForConfirmation: true, - }, - NounsDAOProxyV2: { - args: [ - () => deployment.NounsDAOExecutor.address, - () => deployment.NounsToken.address, - args.noundersdao, - () => deployment.NounsDAOExecutor.address, - () => deployment.NounsDAOLogicV2.address, - args.votingPeriod, - args.votingDelay, - args.proposalThresholdBps, - { - minQuorumVotesBPS: args.minQuorumVotesBPS, - maxQuorumVotesBPS: args.maxQuorumVotesBPS, - quorumCoefficient: parseUnits(args.quorumCoefficient.toString(), 6), - }, - ], - waitForConfirmation: true, - validateDeployment: () => { - const expected = expectedNounsDAOProxyAddress.toLowerCase(); - const actual = deployment.NounsDAOProxyV2.address.toLowerCase(); - if (expected !== actual) { - throw new Error( - `Unexpected Nouns DAO proxy address. Expected: ${expected}. Actual: ${actual}.`, - ); - } - }, - }, - }; - - for (const [name, contract] of Object.entries(contracts)) { - let gasPrice = await ethers.provider.getGasPrice(); - if (!args.autoDeploy) { - const gasInGwei = Math.round(Number(ethers.utils.formatUnits(gasPrice, 'gwei'))); - - promptjs.start(); - - const result = await promptjs.get([ - { - properties: { - gasPrice: { - type: 'integer', - required: true, - description: 'Enter a gas price (gwei)', - default: gasInGwei, - }, - }, - }, - ]); - gasPrice = ethers.utils.parseUnits(result.gasPrice.toString(), 'gwei'); - } - - let nameForFactory: string; - switch (name) { - case 'NounsDAOExecutor': - nameForFactory = 'NounsDAOExecutorTest'; - break; - case 'NounsDAOLogicV2': - nameForFactory = 'NounsDAOLogicV2Harness'; - break; - default: - nameForFactory = name; - break; - } - - const factory = await ethers.getContractFactory(nameForFactory, { - libraries: contract?.libraries?.(), - }); - - const deploymentGas = await factory.signer.estimateGas( - factory.getDeployTransaction( - ...(contract.args?.map(a => (typeof a === 'function' ? a() : a)) ?? []), - { - gasPrice, - }, - ), - ); - const deploymentCost = deploymentGas.mul(gasPrice); - - console.log( - `Estimated cost to deploy ${name}: ${ethers.utils.formatUnits( - deploymentCost, - 'ether', - )} ETH`, - ); - - if (!args.autoDeploy) { - const result = await promptjs.get([ - { - properties: { - confirm: { - pattern: /^(DEPLOY|SKIP|EXIT)$/, - description: - 'Type "DEPLOY" to confirm, "SKIP" to skip this contract, or "EXIT" to exit.', - }, - }, - }, - ]); - if (result.operation === 'SKIP') { - console.log(`Skipping ${name} deployment...`); - continue; - } - if (result.operation === 'EXIT') { - console.log('Exiting...'); - return; - } - } - console.log(`Deploying ${name}...`); - - const deployedContract = await factory.deploy( - ...(contract.args?.map(a => (typeof a === 'function' ? a() : a)) ?? []), - { - gasPrice, - }, - ); - - if (contract.waitForConfirmation) { - await deployedContract.deployed(); - } - - deployment[name as ContractNamesDAOV2] = { - name: nameForFactory, - instance: deployedContract, - address: deployedContract.address, - constructorArguments: contract.args?.map(a => (typeof a === 'function' ? a() : a)) ?? [], - libraries: contract?.libraries?.() ?? {}, - }; - - contract.validateDeployment?.(); - - console.log(`${name} contract deployed to ${deployedContract.address}`); - } - - return deployment; - }); diff --git a/packages/nouns-contracts/tasks/deploy-test-token.ts b/packages/nouns-contracts/tasks/deploy-test-token.ts index 696818d119..917f376396 100644 --- a/packages/nouns-contracts/tasks/deploy-test-token.ts +++ b/packages/nouns-contracts/tasks/deploy-test-token.ts @@ -1,5 +1,5 @@ import { task } from 'hardhat/config'; -import { ContractName, DeployedContract } from './types'; +import { DeployedContract } from './types'; async function delay(seconds: number) { return new Promise(resolve => setTimeout(resolve, 1000 * seconds)); diff --git a/packages/nouns-contracts/tasks/deploy-v2-logic.ts b/packages/nouns-contracts/tasks/deploy-v2-logic.ts deleted file mode 100644 index 1d52ac6e84..0000000000 --- a/packages/nouns-contracts/tasks/deploy-v2-logic.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { task } from 'hardhat/config'; -import promptjs from 'prompt'; -import { - getDeploymentConfirmationWithPrompt, - getGasPriceWithPrompt, - printEstimatedCost, -} from './utils'; - -promptjs.colors = false; -promptjs.message = '> '; -promptjs.delimiter = ''; - -task('deploy-v2-logic', 'Deploys NounsDAOLogicV2').setAction(async (_args, { ethers, run }) => { - const factory = await ethers.getContractFactory('NounsDAOLogicV2'); - const signer = (await ethers.getSigners())[0]; - - const gasPrice = await getGasPriceWithPrompt(ethers); - await printEstimatedCost(factory, gasPrice); - - const deployConfirmed = await getDeploymentConfirmationWithPrompt(); - if (!deployConfirmed) { - console.log('Exiting'); - return; - } - - console.log('Deploying...'); - const contract = await factory.deploy({ gasPrice }); - await contract.deployed(); - console.log(`Transaction hash: ${contract.deployTransaction.hash} \n`); - console.log(`NounsDAOLogicV2 deployed to ${contract.address}`); - - await new Promise(f => setTimeout(f, 60000)); - - console.log('Verifying on Etherscan...'); - await run('verify:verify', { - address: contract.address, - constructorArguments: [], - }); - console.log('Verified'); -}); diff --git a/packages/nouns-contracts/tasks/deploy.ts b/packages/nouns-contracts/tasks/deploy.ts deleted file mode 100644 index f76de429db..0000000000 --- a/packages/nouns-contracts/tasks/deploy.ts +++ /dev/null @@ -1,298 +0,0 @@ -import { default as NounsAuctionHouseABI } from '../abi/contracts/NounsAuctionHouse.sol/NounsAuctionHouse.json'; -import { ChainId, ContractDeployment, ContractName, DeployedContract } from './types'; -import { Interface } from 'ethers/lib/utils'; -import { task, types } from 'hardhat/config'; -import { constants } from 'ethers'; -import promptjs from 'prompt'; - -promptjs.colors = false; -promptjs.message = '> '; -promptjs.delimiter = ''; - -const proxyRegistries: Record = { - [ChainId.Mainnet]: '0xa5409ec958c83c3f309868babaca7c86dcb077c1', -}; -const wethContracts: Record = { - [ChainId.Mainnet]: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', - [ChainId.Ropsten]: '0xc778417e063141139fce010982780140aa0cd5ab', - [ChainId.Kovan]: '0xd0a1e359811322d97991e03f863a0c30c2cf029c', - [ChainId.Goerli]: '0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6', -}; - -const NOUNS_ART_NONCE_OFFSET = 4; -const AUCTION_HOUSE_PROXY_NONCE_OFFSET = 9; -const GOVERNOR_N_DELEGATOR_NONCE_OFFSET = 12; - -task('deploy', 'Deploys NFTDescriptor, NounsDescriptor, NounsSeeder, and NounsToken') - .addFlag('autoDeploy', 'Deploy all contracts without user interaction') - .addOptionalParam('weth', 'The WETH contract address', undefined, types.string) - .addOptionalParam('noundersdao', 'The nounders DAO contract address', undefined, types.string) - .addOptionalParam( - 'auctionTimeBuffer', - 'The auction time buffer (seconds)', - 5 * 60 /* 5 minutes */, - types.int, - ) - .addOptionalParam( - 'auctionReservePrice', - 'The auction reserve price (wei)', - 1 /* 1 wei */, - types.int, - ) - .addOptionalParam( - 'auctionMinIncrementBidPercentage', - 'The auction min increment bid percentage (out of 100)', - 2 /* 2% */, - types.int, - ) - .addOptionalParam( - 'auctionDuration', - 'The auction duration (seconds)', - 60 * 60 * 24 /* 24 hours */, - types.int, - ) - .addOptionalParam( - 'timelockDelay', - 'The timelock delay (seconds)', - 60 * 60 * 24 * 2 /* 2 days */, - types.int, - ) - .addOptionalParam( - 'votingPeriod', - 'The voting period (blocks)', - Math.round(4 * 60 * 24 * (60 / 13)) /* 4 days (13s blocks) */, - types.int, - ) - .addOptionalParam( - 'votingDelay', - 'The voting delay (blocks)', - Math.round(3 * 60 * 24 * (60 / 13)) /* 3 days (13s blocks) */, - types.int, - ) - .addOptionalParam( - 'proposalThresholdBps', - 'The proposal threshold (basis points)', - 100 /* 1% */, - types.int, - ) - .addOptionalParam( - 'quorumVotesBps', - 'Votes required for quorum (basis points)', - 1_000 /* 10% */, - types.int, - ) - .setAction(async (args, { ethers }) => { - const network = await ethers.provider.getNetwork(); - const [deployer] = await ethers.getSigners(); - - // prettier-ignore - const proxyRegistryAddress = proxyRegistries[network.chainId] ?? constants.AddressZero - - if (!args.noundersdao) { - console.log( - `Nounders DAO address not provided. Setting to deployer (${deployer.address})...`, - ); - args.noundersdao = deployer.address; - } - if (!args.weth) { - const deployedWETHContract = wethContracts[network.chainId]; - if (!deployedWETHContract) { - throw new Error( - `Can not auto-detect WETH contract on chain ${network.name}. Provide it with the --weth arg.`, - ); - } - args.weth = deployedWETHContract; - } - - const nonce = await deployer.getTransactionCount(); - const expectedNounsArtAddress = ethers.utils.getContractAddress({ - from: deployer.address, - nonce: nonce + NOUNS_ART_NONCE_OFFSET, - }); - const expectedAuctionHouseProxyAddress = ethers.utils.getContractAddress({ - from: deployer.address, - nonce: nonce + AUCTION_HOUSE_PROXY_NONCE_OFFSET, - }); - const expectedNounsDAOProxyAddress = ethers.utils.getContractAddress({ - from: deployer.address, - nonce: nonce + GOVERNOR_N_DELEGATOR_NONCE_OFFSET, - }); - const deployment: Record = {} as Record< - ContractName, - DeployedContract - >; - const contracts: Record = { - NFTDescriptorV2: {}, - SVGRenderer: {}, - NounsDescriptorV2: { - args: [expectedNounsArtAddress, () => deployment.SVGRenderer.address], - libraries: () => ({ - NFTDescriptorV2: deployment.NFTDescriptorV2.address, - }), - }, - Inflator: {}, - NounsArt: { - args: [() => deployment.NounsDescriptorV2.address, () => deployment.Inflator.address], - }, - NounsSeeder: {}, - NounsToken: { - args: [ - args.noundersdao, - expectedAuctionHouseProxyAddress, - () => deployment.NounsDescriptorV2.address, - () => deployment.NounsSeeder.address, - proxyRegistryAddress, - ], - }, - NounsAuctionHouse: { - waitForConfirmation: true, - }, - NounsAuctionHouseProxyAdmin: {}, - NounsAuctionHouseProxy: { - args: [ - () => deployment.NounsAuctionHouse.address, - () => deployment.NounsAuctionHouseProxyAdmin.address, - () => - new Interface(NounsAuctionHouseABI).encodeFunctionData('initialize', [ - deployment.NounsToken.address, - args.weth, - args.auctionTimeBuffer, - args.auctionReservePrice, - args.auctionMinIncrementBidPercentage, - args.auctionDuration, - ]), - ], - waitForConfirmation: true, - validateDeployment: () => { - const expected = expectedAuctionHouseProxyAddress.toLowerCase(); - const actual = deployment.NounsAuctionHouseProxy.address.toLowerCase(); - if (expected !== actual) { - throw new Error( - `Unexpected auction house proxy address. Expected: ${expected}. Actual: ${actual}.`, - ); - } - }, - }, - NounsDAOExecutor: { - args: [expectedNounsDAOProxyAddress, args.timelockDelay], - }, - NounsDAOLogicV1: { - waitForConfirmation: true, - }, - NounsDAOProxy: { - args: [ - () => deployment.NounsDAOExecutor.address, - () => deployment.NounsToken.address, - args.noundersdao, - () => deployment.NounsDAOExecutor.address, - () => deployment.NounsDAOLogicV1.address, - args.votingPeriod, - args.votingDelay, - args.proposalThresholdBps, - args.quorumVotesBps, - ], - waitForConfirmation: true, - validateDeployment: () => { - const expected = expectedNounsDAOProxyAddress.toLowerCase(); - const actual = deployment.NounsDAOProxy.address.toLowerCase(); - if (expected !== actual) { - throw new Error( - `Unexpected Nouns DAO proxy address. Expected: ${expected}. Actual: ${actual}.`, - ); - } - }, - }, - }; - - for (const [name, contract] of Object.entries(contracts)) { - let gasPrice = await ethers.provider.getGasPrice(); - if (!args.autoDeploy) { - const gasInGwei = Math.round(Number(ethers.utils.formatUnits(gasPrice, 'gwei'))); - - promptjs.start(); - - const result = await promptjs.get([ - { - properties: { - gasPrice: { - type: 'integer', - required: true, - description: 'Enter a gas price (gwei)', - default: gasInGwei, - }, - }, - }, - ]); - gasPrice = ethers.utils.parseUnits(result.gasPrice.toString(), 'gwei'); - } - - const factory = await ethers.getContractFactory(name, { - libraries: contract?.libraries?.(), - }); - - const deploymentGas = await factory.signer.estimateGas( - factory.getDeployTransaction( - ...(contract.args?.map(a => (typeof a === 'function' ? a() : a)) ?? []), - { - gasPrice, - }, - ), - ); - const deploymentCost = deploymentGas.mul(gasPrice); - - console.log( - `Estimated cost to deploy ${name}: ${ethers.utils.formatUnits( - deploymentCost, - 'ether', - )} ETH`, - ); - - if (!args.autoDeploy) { - const result = await promptjs.get([ - { - properties: { - confirm: { - pattern: /^(DEPLOY|SKIP|EXIT)$/, - description: - 'Type "DEPLOY" to confirm, "SKIP" to skip this contract, or "EXIT" to exit.', - }, - }, - }, - ]); - if (result.operation === 'SKIP') { - console.log(`Skipping ${name} deployment...`); - continue; - } - if (result.operation === 'EXIT') { - console.log('Exiting...'); - return; - } - } - console.log(`Deploying ${name}...`); - - const deployedContract = await factory.deploy( - ...(contract.args?.map(a => (typeof a === 'function' ? a() : a)) ?? []), - { - gasPrice, - }, - ); - - if (contract.waitForConfirmation) { - await deployedContract.deployed(); - } - - deployment[name as ContractName] = { - name, - instance: deployedContract, - address: deployedContract.address, - constructorArguments: contract.args?.map(a => (typeof a === 'function' ? a() : a)) ?? [], - libraries: contract?.libraries?.() ?? {}, - }; - - contract.validateDeployment?.(); - - console.log(`${name} contract deployed to ${deployedContract.address}`); - } - - return deployment; - }); diff --git a/packages/nouns-contracts/tasks/descriptor-v1-export-abi.ts b/packages/nouns-contracts/tasks/descriptor-v1-export-abi.ts deleted file mode 100644 index cd18bf07ad..0000000000 --- a/packages/nouns-contracts/tasks/descriptor-v1-export-abi.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { writeFileSync } from 'fs'; -import { task, types } from 'hardhat/config'; -import path from 'path'; -import ImageData from '../files/image-data-v1.json'; - -task( - 'descriptor-v1-export-abi', - 'Exports the image-data to abi files to be able to load from forge tests', -) - .addOptionalParam( - 'exportPath', - 'Where to save abi encoded files to be used in forge tests', - path.join(__dirname, '../test/foundry/files/descriptor_v1/'), - ) - .setAction(async ({ exportPath }, { ethers }) => { - const { bgcolors, palette, images } = ImageData; - let { bodies, accessories, heads, glasses } = images; - - const abiEncoded = ethers.utils.defaultAbiCoder.encode( - ['string[]', 'string[]', 'bytes[]', 'bytes[]', 'bytes[]', 'bytes[]'], - [ - bgcolors, - palette, - bodies.map(({ data }) => data), - accessories.map(({ data }) => data), - heads.map(({ data }) => data), - glasses.map(({ data }) => data), - ], - ); - - const filepath = path.join(exportPath, 'image-data.abi'); - writeFileSync(filepath, abiEncoded); - console.log(`Saved image-data to ${filepath}`); - }); diff --git a/packages/nouns-contracts/tasks/index.ts b/packages/nouns-contracts/tasks/index.ts index d3b95f6f8d..9ce6237ea9 100644 --- a/packages/nouns-contracts/tasks/index.ts +++ b/packages/nouns-contracts/tasks/index.ts @@ -1,28 +1,11 @@ export * from './accounts'; export * from './create-proposal'; -export * from './deploy'; -export * from './deploy-ci'; -export * from './deploy-local'; -export * from './deploy-and-configure'; -export * from './mint-noun'; export * from './populate-descriptor'; -export * from './run-local'; -export * from './verify-etherscan'; -export * from './update-configs'; export * from './descriptor-art-to-console'; -export * from './descriptor-v1-export-abi'; export * from './deploy-descriptor-v2'; -export * from './deploy-short-times'; -export * from './deploy-and-configure-short-times'; export * from './populate-descriptor-via-proposal'; export * from './deploy-test-token'; -export * from './populate-descriptor-v1'; export * from './upgrade-descriptor-via-proposal'; -export * from './deploy-v2-logic'; -export * from './verify-etherscan-daov2'; -export * from './update-configs-daov2'; -export * from './deploy-short-times-daov1'; -export * from './deploy-and-configure-short-times-daov1'; export * from './deploy-local-dao-v3'; export * from './run-local-dao-v3'; export * from './deploy-short-times-dao-v3'; diff --git a/packages/nouns-contracts/tasks/mint-noun.ts b/packages/nouns-contracts/tasks/mint-noun.ts deleted file mode 100644 index 0a840a0692..0000000000 --- a/packages/nouns-contracts/tasks/mint-noun.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { Result } from 'ethers/lib/utils'; -import { task, types } from 'hardhat/config'; - -task('mint-noun', 'Mints a Noun') - .addOptionalParam( - 'nounsToken', - 'The `NounsToken` contract address', - '0xCf7Ed3AccA5a467e9e704C703E8D87F634fB0Fc9', - types.string, - ) - .setAction(async ({ nounsToken }, { ethers }) => { - const nftFactory = await ethers.getContractFactory('NounsToken'); - const nftContract = nftFactory.attach(nounsToken); - - const receipt = await (await nftContract.mint()).wait(); - const nounCreated = receipt.events?.[1]; - const { tokenId } = nounCreated?.args as Result; - - console.log(`Noun minted with ID: ${tokenId.toString()}.`); - }); diff --git a/packages/nouns-contracts/tasks/populate-descriptor-v1.ts b/packages/nouns-contracts/tasks/populate-descriptor-v1.ts deleted file mode 100644 index 93f7415f5f..0000000000 --- a/packages/nouns-contracts/tasks/populate-descriptor-v1.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { task, types } from 'hardhat/config'; -import ImageData from '../files/image-data-v1.json'; -import { chunkArray } from '../utils'; - -task('populate-descriptor-v1', 'Populates the descriptor with color palettes and Noun parts') - .addOptionalParam( - 'nftDescriptor', - 'The `NFTDescriptor` contract address', - '0x5FbDB2315678afecb367f032d93F642f64180aa3', - types.string, - ) - .addOptionalParam( - 'nounsDescriptor', - 'The `NounsDescriptor` contract address', - '0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512', - types.string, - ) - .setAction(async ({ nftDescriptor, nounsDescriptor }, { ethers }) => { - const descriptorFactory = await ethers.getContractFactory('NounsDescriptor', { - libraries: { - NFTDescriptor: nftDescriptor, - }, - }); - const descriptorContract = descriptorFactory.attach(nounsDescriptor); - - const { bgcolors, palette, images } = ImageData; - const { bodies, accessories, heads, glasses } = images; - - // Chunk head and accessory population due to high gas usage - await descriptorContract.addManyBackgrounds(bgcolors); - await descriptorContract.addManyColorsToPalette(0, palette); - await descriptorContract.addManyBodies(bodies.map(({ data }) => data)); - - const accessoryChunk = chunkArray(accessories, 10); - for (const chunk of accessoryChunk) { - await descriptorContract.addManyAccessories(chunk.map(({ data }) => data)); - } - - const headChunk = chunkArray(heads, 10); - for (const chunk of headChunk) { - await descriptorContract.addManyHeads(chunk.map(({ data }) => data)); - } - - await descriptorContract.addManyGlasses(glasses.map(({ data }) => data)); - - console.log('Descriptor populated with palettes and parts.'); - }); diff --git a/packages/nouns-contracts/tasks/run-local.ts b/packages/nouns-contracts/tasks/run-local.ts deleted file mode 100644 index 9fb16c470e..0000000000 --- a/packages/nouns-contracts/tasks/run-local.ts +++ /dev/null @@ -1,71 +0,0 @@ -import { TASK_COMPILE, TASK_NODE } from 'hardhat/builtin-tasks/task-names'; -import { task } from 'hardhat/config'; - -task( - 'run-local', - 'Start a hardhat node, deploy contracts, and execute setup transactions', -).setAction(async (_, { ethers, run }) => { - await run(TASK_COMPILE); - - await Promise.race([ - run(TASK_NODE, { hostname: '0.0.0.0' }), - new Promise(resolve => setTimeout(resolve, 2_000)), - ]); - - const contracts = await run('deploy-local'); - - await run('populate-descriptor', { - nftDescriptor: contracts.NFTDescriptorV2.instance.address, - nounsDescriptor: contracts.NounsDescriptorV2.instance.address, - }); - - await contracts.NounsAuctionHouse.instance - .attach(contracts.NounsAuctionHouseProxy.instance.address) - .unpause({ - gasLimit: 1_000_000, - }); - - // Transfer ownership - const executorAddress = contracts.NounsDAOExecutor.instance.address; - await contracts.NounsDescriptorV2.instance.transferOwnership(executorAddress); - await contracts.NounsToken.instance.transferOwnership(executorAddress); - await contracts.NounsAuctionHouseProxyAdmin.instance.transferOwnership(executorAddress); - await contracts.NounsAuctionHouse.instance - .attach(contracts.NounsAuctionHouseProxy.instance.address) - .transferOwnership(executorAddress); - console.log( - 'Transferred ownership of the descriptor, token, and proxy admin contracts to the executor.', - ); - - // await run('create-proposal', { - // nounsDaoProxy: contracts.NounsDAOProxyV2.instance.address, - // }); - - const { chainId } = await ethers.provider.getNetwork(); - - const accounts = { - 'Account #0': { - Address: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266', - 'Private Key': '0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80', - }, - 'Account #1': { - Address: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8', - 'Private Key': '0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d', - }, - }; - - console.table(accounts); - console.log( - `Noun contracts deployed to local node at http://localhost:8545 (Chain ID: ${chainId})`, - ); - console.log(`Auction House Proxy address: ${contracts.NounsAuctionHouseProxy.instance.address}`); - console.log(`Nouns ERC721 address: ${contracts.NounsToken.instance.address}`); - console.log(`Nouns DAO Executor address: ${contracts.NounsDAOExecutor.instance.address}`); - console.log(`Nouns DAO Proxy address: ${contracts.NounsDAOProxyV2.instance.address}`); - - await ethers.provider.send('evm_setIntervalMining', [12_000]); - - await new Promise(() => { - /* keep node alive until this process is killed */ - }); -}); diff --git a/packages/nouns-contracts/tasks/types/index.ts b/packages/nouns-contracts/tasks/types/index.ts index c943c8a787..7f9a6953a2 100644 --- a/packages/nouns-contracts/tasks/types/index.ts +++ b/packages/nouns-contracts/tasks/types/index.ts @@ -9,26 +9,24 @@ export enum ChainId { Sepolia = 11155111, } -// prettier-ignore -export type DescriptorV1ContractNames = 'NFTDescriptor' | 'NounsDescriptor'; -// prettier-ignore -export type DescriptorV2ContractNames = 'NFTDescriptorV2' | 'NounsDescriptorV2' | 'SVGRenderer' | 'NounsArt' | 'Inflator'; -// prettier-ignore -export type ContractName = DescriptorV2ContractNames | 'NounsSeeder' | 'NounsToken' | 'NounsAuctionHouse' | 'NounsAuctionHouseProxyAdmin' | 'NounsAuctionHouseProxy' | 'NounsDAOExecutor' | 'NounsDAOLogicV1' | 'NounsDAOProxy'; -// prettier-ignore -export type ContractNameDescriptorV1 = DescriptorV1ContractNames | 'NounsSeeder' | 'NounsToken' | 'NounsAuctionHouse' | 'NounsAuctionHouseProxyAdmin' | 'NounsAuctionHouseProxy' | 'NounsDAOExecutor' | 'NounsDAOLogicV1' | 'NounsDAOProxy'; -// prettier-ignore -export type ContractNamesDAOV2 = Exclude | 'NounsDAOLogicV2' | 'NounsDAOProxyV2'; - export type ContractNamesDAOV3 = - | Exclude - | 'NounsDAOLogicV3' + | 'NFTDescriptorV2' + | 'NounsDescriptorV2' + | 'SVGRenderer' + | 'NounsArt' + | 'Inflator' + | 'NounsSeeder' + | 'NounsToken' + | 'NounsAuctionHouse' + | 'NounsAuctionHouseProxyAdmin' + | 'NounsAuctionHouseProxy' + | 'NounsDAOLogicV4' | 'NounsDAOProxyV3' - | 'NounsDAOV3Admin' - | 'NounsDAOV3DynamicQuorum' - | 'NounsDAOV3Proposals' - | 'NounsDAOV3Votes' - | 'NounsDAOV3Fork' + | 'NounsDAOAdmin' + | 'NounsDAODynamicQuorum' + | 'NounsDAOProposals' + | 'NounsDAOVotes' + | 'NounsDAOFork' | 'NounsDAOForkEscrow' | 'ForkDAODeployer' | 'NounsTokenFork' diff --git a/packages/nouns-contracts/tasks/update-configs-dao-v3.ts b/packages/nouns-contracts/tasks/update-configs-dao-v3.ts index a999eed5eb..29e8e52b5a 100644 --- a/packages/nouns-contracts/tasks/update-configs-dao-v3.ts +++ b/packages/nouns-contracts/tasks/update-configs-dao-v3.ts @@ -27,7 +27,7 @@ task('update-configs-dao-v3', 'Write the deployed addresses to the SDK and subgr nounsAuctionHouseProxyAdmin: contracts.NounsAuctionHouseProxyAdmin.address, nounsDaoExecutor: contracts.NounsDAOExecutorProxy.address, nounsDAOProxy: contracts.NounsDAOProxyV3.address, - nounsDAOLogicV1: contracts.NounsDAOLogicV3.address, + nounsDAOLogicV1: contracts.NounsDAOLogicV4.address, nounsDAOData: contracts.NounsDAODataProxy.address, }; writeFileSync(addressesPath, JSON.stringify(addresses, null, 2)); @@ -58,7 +58,7 @@ task('update-configs-dao-v3', 'Write the deployed addresses to the SDK and subgr startBlock: contracts.NounsDAOProxyV3.instance.deployTransaction.blockNumber, }, nounsDAOData: { - addresses: contracts.NounsDAODataProxy.address, + address: contracts.NounsDAODataProxy.address, startBlock: contracts.NounsDAODataProxy.instance.deployTransaction.blockNumber, }, }; diff --git a/packages/nouns-contracts/tasks/update-configs-daov2.ts b/packages/nouns-contracts/tasks/update-configs-daov2.ts deleted file mode 100644 index 96b1fe33a9..0000000000 --- a/packages/nouns-contracts/tasks/update-configs-daov2.ts +++ /dev/null @@ -1,63 +0,0 @@ -import { task, types } from 'hardhat/config'; -import { ContractNamesDAOV2, DeployedContract } from './types'; -import { readFileSync, writeFileSync } from 'fs'; -import { execSync } from 'child_process'; -import { join } from 'path'; - -task('update-configs-daov2', 'Write the deployed addresses to the SDK and subgraph configs') - .addParam('contracts', 'Contract objects from the deployment', undefined, types.json) - .setAction( - async ( - { contracts }: { contracts: Record }, - { ethers }, - ) => { - const { name: network, chainId } = await ethers.provider.getNetwork(); - - // Update SDK addresses - const sdkPath = join(__dirname, '../../nouns-sdk'); - const addressesPath = join(sdkPath, 'src/contract/addresses.json'); - const addresses = JSON.parse(readFileSync(addressesPath, 'utf8')); - addresses[chainId] = { - nounsToken: contracts.NounsToken.address, - nounsSeeder: contracts.NounsSeeder.address, - nounsDescriptor: contracts.NounsDescriptorV2.address, - nftDescriptor: contracts.NFTDescriptorV2.address, - nounsAuctionHouse: contracts.NounsAuctionHouse.address, - nounsAuctionHouseProxy: contracts.NounsAuctionHouseProxy.address, - nounsAuctionHouseProxyAdmin: contracts.NounsAuctionHouseProxyAdmin.address, - nounsDaoExecutor: contracts.NounsDAOExecutor.address, - nounsDAOProxy: contracts.NounsDAOProxyV2.address, - nounsDAOLogicV2: contracts.NounsDAOLogicV2.address, - }; - writeFileSync(addressesPath, JSON.stringify(addresses, null, 2)); - try { - execSync('yarn build', { - cwd: sdkPath, - }); - } catch { - console.log('Failed to re-build `@nouns/sdk`. Please rebuild manually.'); - } - console.log('Addresses written to the Nouns SDK.'); - - // Generate subgraph config - const configName = `${network}-fork`; - const subgraphConfigPath = join(__dirname, `../../nouns-subgraph/config/${configName}.json`); - const subgraphConfig = { - network, - nounsToken: { - address: contracts.NounsToken.address, - startBlock: contracts.NounsToken.instance.deployTransaction.blockNumber, - }, - nounsAuctionHouse: { - address: contracts.NounsAuctionHouseProxy.address, - startBlock: contracts.NounsAuctionHouseProxy.instance.deployTransaction.blockNumber, - }, - nounsDAO: { - address: contracts.NounsDAOProxyV2.address, - startBlock: contracts.NounsDAOProxyV2.instance.deployTransaction.blockNumber, - }, - }; - writeFileSync(subgraphConfigPath, JSON.stringify(subgraphConfig, null, 2)); - console.log('Subgraph config has been generated.'); - }, - ); diff --git a/packages/nouns-contracts/tasks/update-configs.ts b/packages/nouns-contracts/tasks/update-configs.ts deleted file mode 100644 index c82bb44a79..0000000000 --- a/packages/nouns-contracts/tasks/update-configs.ts +++ /dev/null @@ -1,69 +0,0 @@ -import { task, types } from 'hardhat/config'; -import { ContractName, ContractNameDescriptorV1, DeployedContract } from './types'; -import { readFileSync, writeFileSync } from 'fs'; -import { execSync } from 'child_process'; -import { join } from 'path'; - -task('update-configs', 'Write the deployed addresses to the SDK and subgraph configs') - .addParam('contracts', 'Contract objects from the deployment', undefined, types.json) - .setAction( - async ( - { - contracts, - }: { contracts: Record }, - { ethers }, - ) => { - const { name: network, chainId } = await ethers.provider.getNetwork(); - - // Update SDK addresses - const sdkPath = join(__dirname, '../../nouns-sdk'); - const addressesPath = join(sdkPath, 'src/contract/addresses.json'); - const addresses = JSON.parse(readFileSync(addressesPath, 'utf8')); - addresses[chainId] = { - nounsToken: contracts.NounsToken.address, - nounsSeeder: contracts.NounsSeeder.address, - nounsDescriptor: contracts.NounsDescriptorV2 - ? contracts.NounsDescriptorV2.address - : contracts.NounsDescriptor.address, - nftDescriptor: contracts.NFTDescriptorV2 - ? contracts.NFTDescriptorV2.address - : contracts.NFTDescriptor.address, - nounsAuctionHouse: contracts.NounsAuctionHouse.address, - nounsAuctionHouseProxy: contracts.NounsAuctionHouseProxy.address, - nounsAuctionHouseProxyAdmin: contracts.NounsAuctionHouseProxyAdmin.address, - nounsDaoExecutor: contracts.NounsDAOExecutor.address, - nounsDAOProxy: contracts.NounsDAOProxy.address, - nounsDAOLogicV1: contracts.NounsDAOLogicV1.address, - }; - writeFileSync(addressesPath, JSON.stringify(addresses, null, 2)); - try { - execSync('yarn build', { - cwd: sdkPath, - }); - } catch { - console.log('Failed to re-build `@nouns/sdk`. Please rebuild manually.'); - } - console.log('Addresses written to the Nouns SDK.'); - - // Generate subgraph config - const configName = `${network}-fork`; - const subgraphConfigPath = join(__dirname, `../../nouns-subgraph/config/${configName}.json`); - const subgraphConfig = { - network, - nounsToken: { - address: contracts.NounsToken.address, - startBlock: contracts.NounsToken.instance.deployTransaction.blockNumber, - }, - nounsAuctionHouse: { - address: contracts.NounsAuctionHouseProxy.address, - startBlock: contracts.NounsAuctionHouseProxy.instance.deployTransaction.blockNumber, - }, - nounsDAO: { - address: contracts.NounsDAOProxy.address, - startBlock: contracts.NounsDAOProxy.instance.deployTransaction.blockNumber, - }, - }; - writeFileSync(subgraphConfigPath, JSON.stringify(subgraphConfig, null, 2)); - console.log('Subgraph config has been generated.'); - }, - ); diff --git a/packages/nouns-contracts/tasks/upgrade-descriptor-via-proposal.ts b/packages/nouns-contracts/tasks/upgrade-descriptor-via-proposal.ts index 86455f7710..cf660de49b 100644 --- a/packages/nouns-contracts/tasks/upgrade-descriptor-via-proposal.ts +++ b/packages/nouns-contracts/tasks/upgrade-descriptor-via-proposal.ts @@ -10,8 +10,8 @@ task('upgrade-descriptor-via-proposal', 'Upgrade NounsToken to use Descriptor V2 const signatures = ['setDescriptor(address)']; const calldatas = [ethers.utils.defaultAbiCoder.encode(['address'], [descriptor])]; - const gov = (await ethers.getContractFactory('NounsDAOLogicV1')).attach(dao); - const propTx = await gov.propose( + const gov = (await ethers.getContractFactory('NounsDAOLogicV4')).attach(dao); + const propTx = await gov['propose(address[],uint256[],string[],bytes[],string)']( targets, values, signatures, diff --git a/packages/nouns-contracts/tasks/utils/index.ts b/packages/nouns-contracts/tasks/utils/index.ts index 2e3a73a91e..aad57140d4 100644 --- a/packages/nouns-contracts/tasks/utils/index.ts +++ b/packages/nouns-contracts/tasks/utils/index.ts @@ -1,63 +1,12 @@ -import { HardhatEthersHelpers } from '@nomiclabs/hardhat-ethers/types'; -import type { BigNumber, ContractFactory, ethers as ethersType } from 'ethers'; -import { ethers, utils } from 'ethers'; +import { ethers } from 'ethers'; import promptjs from 'prompt'; import { deflateRawSync } from 'zlib'; -import { ContractName, ContractRow, DeployedContract } from '../types'; +import { ContractNamesDAOV3, ContractRow, DeployedContract } from '../types'; promptjs.colors = false; promptjs.message = '> '; promptjs.delimiter = ''; -export async function getGasPriceWithPrompt( - ethers: typeof ethersType & HardhatEthersHelpers, -): Promise { - const gasPrice = await ethers.provider.getGasPrice(); - const gasInGwei = Math.round(Number(ethers.utils.formatUnits(gasPrice, 'gwei'))); - - promptjs.start(); - - let result = await promptjs.get([ - { - properties: { - gasPrice: { - type: 'integer', - required: true, - description: 'Enter a gas price (gwei)', - default: gasInGwei, - }, - }, - }, - ]); - - return ethers.utils.parseUnits(result.gasPrice.toString(), 'gwei'); -} - -export async function getDeploymentConfirmationWithPrompt(): Promise { - const result = await promptjs.get([ - { - properties: { - confirm: { - type: 'string', - description: 'Type "DEPLOY" to confirm:', - }, - }, - }, - ]); - - return result.confirm == 'DEPLOY'; -} - -export async function printEstimatedCost(factory: ContractFactory, gasPrice: BigNumber) { - const deploymentGas = await factory.signer.estimateGas( - factory.getDeployTransaction({ gasPrice }), - ); - const deploymentCost = deploymentGas.mul(gasPrice); - console.log( - `Estimated cost to deploy NounsDAOLogicV2: ${utils.formatUnits(deploymentCost, 'ether')} ETH`, - ); -} - export function dataToDescriptorInput(data: string[]): { encodedCompressed: string; originalLength: number; @@ -78,7 +27,7 @@ export function dataToDescriptorInput(data: string[]): { }; } -export function printContractsTable(contracts: Record) { +export function printContractsTable(contracts: Record) { console.table( Object.values(contracts).reduce( (acc: Record, contract: DeployedContract) => { diff --git a/packages/nouns-contracts/tasks/verify-etherscan-dao-v3.ts b/packages/nouns-contracts/tasks/verify-etherscan-dao-v3.ts index 152f74e552..5dc1115479 100644 --- a/packages/nouns-contracts/tasks/verify-etherscan-dao-v3.ts +++ b/packages/nouns-contracts/tasks/verify-etherscan-dao-v3.ts @@ -1,5 +1,5 @@ import { task, types } from 'hardhat/config'; -import { ContractName, ContractNamesDAOV3, DeployedContract } from './types'; +import { ContractNamesDAOV3, DeployedContract } from './types'; // prettier-ignore // These contracts require a fully qualified name to be passed because diff --git a/packages/nouns-contracts/tasks/verify-etherscan-daov2.ts b/packages/nouns-contracts/tasks/verify-etherscan-daov2.ts deleted file mode 100644 index 2a5404cf8f..0000000000 --- a/packages/nouns-contracts/tasks/verify-etherscan-daov2.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { task, types } from 'hardhat/config'; -import { ContractName, ContractNamesDAOV2, DeployedContract } from './types'; - -// prettier-ignore -// These contracts require a fully qualified name to be passed because -// they share bytecode with the underlying contract. -const nameToFullyQualifiedName: Record = { - NounsAuctionHouseProxy: 'contracts/proxies/NounsAuctionHouseProxy.sol:NounsAuctionHouseProxy', - NounsAuctionHouseProxyAdmin: 'contracts/proxies/NounsAuctionHouseProxyAdmin.sol:NounsAuctionHouseProxyAdmin', - NounsDAOLogicV2Harness: 'contracts/test/NounsDAOLogicV2Harness.sol:NounsDAOLogicV2Harness' -}; - -task('verify-etherscan-daov2', 'Verify the Solidity contracts on Etherscan') - .addParam('contracts', 'Contract objects from the deployment', undefined, types.json) - .setAction( - async ({ contracts }: { contracts: Record }, hre) => { - for (const [, contract] of Object.entries(contracts)) { - console.log(`verifying ${contract.name}...`); - try { - const code = await contract.instance?.provider.getCode(contract.address); - if (code === '0x') { - console.log( - `${contract.name} contract deployment has not completed. waiting to verify...`, - ); - await contract.instance?.deployed(); - } - await hre.run('verify:verify', { - ...contract, - contract: nameToFullyQualifiedName[contract.name], - }); - } catch ({ message }) { - if ((message as string).includes('Reason: Already Verified')) { - continue; - } - console.error(message); - } - } - }, - ); diff --git a/packages/nouns-contracts/tasks/verify-etherscan.ts b/packages/nouns-contracts/tasks/verify-etherscan.ts deleted file mode 100644 index c389e80f49..0000000000 --- a/packages/nouns-contracts/tasks/verify-etherscan.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { task, types } from 'hardhat/config'; -import { ContractName, DeployedContract } from './types'; - -// prettier-ignore -// These contracts require a fully qualified name to be passed because -// they share bytecode with the underlying contract. -const nameToFullyQualifiedName: Record = { - NounsAuctionHouseProxy: 'contracts/proxies/NounsAuctionHouseProxy.sol:NounsAuctionHouseProxy', - NounsAuctionHouseProxyAdmin: 'contracts/proxies/NounsAuctionHouseProxyAdmin.sol:NounsAuctionHouseProxyAdmin', - NounsDAOLogicV1Harness: 'contracts/test/NounsDAOLogicV1Harness.sol:NounsDAOLogicV1Harness' -}; - -task('verify-etherscan', 'Verify the Solidity contracts on Etherscan') - .addParam('contracts', 'Contract objects from the deployment', undefined, types.json) - .setAction(async ({ contracts }: { contracts: Record }, hre) => { - for (const [, contract] of Object.entries(contracts)) { - console.log(`verifying ${contract.name}...`); - try { - const code = await contract.instance?.provider.getCode(contract.address); - if (code === '0x') { - console.log( - `${contract.name} contract deployment has not completed. waiting to verify...`, - ); - await contract.instance?.deployed(); - } - await hre.run('verify:verify', { - ...contract, - contract: nameToFullyQualifiedName[contract.name], - }); - } catch ({ message }) { - if ((message as string).includes('Reason: Already Verified')) { - continue; - } - console.error(message); - } - } - }); diff --git a/packages/nouns-contracts/test/foundry/DAOUpgradeTo3p1/UpgradeToDAOV3p1MainnetFork.t.sol b/packages/nouns-contracts/test/foundry/DAOUpgradeTo3p1/UpgradeToDAOV3p1MainnetFork.t.sol deleted file mode 100644 index b158b2e3a8..0000000000 --- a/packages/nouns-contracts/test/foundry/DAOUpgradeTo3p1/UpgradeToDAOV3p1MainnetFork.t.sol +++ /dev/null @@ -1,117 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0 -pragma solidity ^0.8.19; - -import 'forge-std/Test.sol'; -import { Strings } from '@openzeppelin/contracts/utils/Strings.sol'; -import { DeployDAOV3LogicMainnet } from '../../../script/DAOV3p1/DeployDAOV3LogicMainnet.s.sol'; -import { ProposeDAOV3p1UpgradeMainnet } from '../../../script/DAOV3p1/ProposeDAOV3p1UpgradeMainnet.s.sol'; -import { NounsToken } from '../../../contracts/NounsToken.sol'; -import { INounsDAOShared } from '../helpers/INounsDAOShared.sol'; -import { NounsDAOStorageV3 } from '../../../contracts/governance/NounsDAOInterfaces.sol'; - -abstract contract UpgradeToDAOV3p1MainnetForkBaseTest is Test { - address public constant NOUNDERS = 0x2573C60a6D127755aA2DC85e342F7da2378a0Cc5; - address public constant WHALE = 0x83fCFe8Ba2FEce9578F0BbaFeD4Ebf5E915045B9; - NounsToken public nouns = NounsToken(0x9C8fF314C9Bc7F6e59A9d9225Fb22946427eDC03); - INounsDAOShared public constant NOUNS_DAO_PROXY_MAINNET = - INounsDAOShared(0x6f3E6272A167e8AcCb32072d08E0957F9c79223d); - address public constant CURRENT_DAO_IMPL = 0xdD1492570beb290a2f309541e1fDdcaAA3f00B61; - - address proposerAddr = vm.addr(0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb); - address origin = makeAddr('origin'); - address newLogic; - - function setUp() public virtual { - vm.createSelectFork(vm.envString('RPC_MAINNET'), 18571818); - - // Get votes - vm.prank(NOUNDERS); - nouns.delegate(proposerAddr); - vm.roll(block.number + 1); - - vm.deal(address(NOUNS_DAO_PROXY_MAINNET), 100 ether); - vm.fee(50 gwei); - vm.txGasPrice(50 gwei); - } - - function propose( - address target, - uint256 value, - string memory signature, - bytes memory data - ) internal returns (uint256 proposalId) { - vm.prank(proposerAddr); - address[] memory targets = new address[](1); - targets[0] = target; - uint256[] memory values = new uint256[](1); - values[0] = value; - string[] memory signatures = new string[](1); - signatures[0] = signature; - bytes[] memory calldatas = new bytes[](1); - calldatas[0] = data; - proposalId = NOUNS_DAO_PROXY_MAINNET.propose(targets, values, signatures, calldatas, 'my proposal'); - } - - function voteAndExecuteProposal(uint256 proposalId) internal { - NounsDAOStorageV3.ProposalCondensed memory propInfo = NOUNS_DAO_PROXY_MAINNET.proposalsV3(proposalId); - - vm.roll(propInfo.startBlock + 1); - vm.prank(proposerAddr, origin); - NOUNS_DAO_PROXY_MAINNET.castRefundableVote(proposalId, 1); - vm.prank(WHALE, origin); - NOUNS_DAO_PROXY_MAINNET.castRefundableVote(proposalId, 1); - - vm.roll(propInfo.endBlock + 1); - NOUNS_DAO_PROXY_MAINNET.queue(proposalId); - - propInfo = NOUNS_DAO_PROXY_MAINNET.proposalsV3(proposalId); - vm.warp(propInfo.eta + 1); - NOUNS_DAO_PROXY_MAINNET.execute(proposalId); - } -} - -contract RefundBeforeTheUpgradeTo3p1MainnetForkTest is UpgradeToDAOV3p1MainnetForkBaseTest { - function test_refundBeforeUpgrade_doesNotRefundOrigin() public { - uint256 originBalanceBefore = origin.balance; - - uint256 proposalId = propose(WHALE, 1 ether, '', ''); - voteAndExecuteProposal(proposalId); - - assertEq(originBalanceBefore, origin.balance); - } -} - -contract UpgradeToDAOV3p1MainnetForkTest is UpgradeToDAOV3p1MainnetForkBaseTest { - function setUp() public override { - super.setUp(); - - // Deploy the latest DAO logic - vm.setEnv('DEPLOYER_PRIVATE_KEY', '0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'); - newLogic = address(new DeployDAOV3LogicMainnet().run()); - - // Propose the upgrade - vm.setEnv('PROPOSER_KEY', '0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb'); - vm.setEnv('DAO_V3_IMPL', Strings.toHexString(uint160(newLogic), 20)); - vm.setEnv('PROPOSAL_DESCRIPTION_FILE', 'test/foundry/DAOUpgradeTo3p1/proposal-description.txt'); - uint256 proposalId = new ProposeDAOV3p1UpgradeMainnet().run(); - - // Execute the upgrade - voteAndExecuteProposal(proposalId); - } - - function test_daoUpgradeWorked() public { - assertTrue(CURRENT_DAO_IMPL != NOUNS_DAO_PROXY_MAINNET.implementation()); - assertEq(newLogic, NOUNS_DAO_PROXY_MAINNET.implementation()); - } - - function test_proposalExecutesAfterTheUpgrade_andRefundGoesToOrigin() public { - uint256 recipientBalanceBefore = WHALE.balance; - uint256 originBalanceBefore = origin.balance; - - uint256 proposalId = propose(WHALE, 1 ether, '', ''); - voteAndExecuteProposal(proposalId); - - assertEq(recipientBalanceBefore + 1 ether, WHALE.balance); - assertGt(origin.balance, originBalanceBefore); - } -} diff --git a/packages/nouns-contracts/test/foundry/NounsAuctionHouseGasSnapshot.t.sol b/packages/nouns-contracts/test/foundry/NounsAuctionHouseGasSnapshot.t.sol new file mode 100644 index 0000000000..a16f300791 --- /dev/null +++ b/packages/nouns-contracts/test/foundry/NounsAuctionHouseGasSnapshot.t.sol @@ -0,0 +1,110 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity ^0.8.15; + +import { INounsAuctionHouse } from '../../contracts/interfaces/INounsAuctionHouse.sol'; +import { INounsAuctionHouseV2 } from '../../contracts/interfaces/INounsAuctionHouseV2.sol'; +import { INounsToken } from '../../contracts/interfaces/INounsToken.sol'; +import { DeployUtils } from './helpers/DeployUtils.sol'; +import { AuctionHouseUpgrader } from './helpers/AuctionHouseUpgrader.sol'; +import { NounsAuctionHouseProxy } from '../../contracts/proxies/NounsAuctionHouseProxy.sol'; +import { NounsAuctionHouseProxyAdmin } from '../../contracts/proxies/NounsAuctionHouseProxyAdmin.sol'; + +abstract contract NounsAuctionHouseBaseTest is DeployUtils { + INounsAuctionHouse auctionHouse; + INounsToken nouns; + address noundersDAO = makeAddr('noundersDAO'); + address owner = makeAddr('owner'); + NounsAuctionHouseProxy auctionHouseProxy; + NounsAuctionHouseProxyAdmin proxyAdmin; + uint256[] nounIds; + + function setUp() public virtual { + ( + NounsAuctionHouseProxy auctionHouseProxy_, + NounsAuctionHouseProxyAdmin proxyAdmin_ + ) = _deployAuctionHouseV1AndToken(owner, noundersDAO, address(0)); + auctionHouseProxy = auctionHouseProxy_; + proxyAdmin = proxyAdmin_; + + auctionHouse = INounsAuctionHouse(address(auctionHouseProxy_)); + + vm.prank(owner); + auctionHouse.unpause(); + } +} + +contract NounsAuctionHouse_GasSnapshot is NounsAuctionHouseBaseTest { + function test_createOneBid() public { + auctionHouse.createBid{ value: 1 ether }(1); + } + + function test_createTwoBids() public { + auctionHouse.createBid{ value: 1 ether }(1); + auctionHouse.createBid{ value: 1.1 ether }(1); + } + + function test_settleCurrentAndCreateNewAuction() public { + vm.warp(block.timestamp + 1.1 days); + + auctionHouse.settleCurrentAndCreateNewAuction(); + } +} + +contract NounsAuctionHouseV2_GasSnapshot is NounsAuctionHouse_GasSnapshot { + function setUp() public virtual override { + super.setUp(); + AuctionHouseUpgrader.upgradeAuctionHouse(owner, proxyAdmin, auctionHouseProxy); + } +} + +contract NounsAuctionHouseV2WarmedUp_GasSnapshot is NounsAuctionHouseV2_GasSnapshot { + function setUp() public override { + super.setUp(); + INounsAuctionHouseV2(address(auctionHouse)).warmUpSettlementState(1, 4); + } +} + +contract NounsAuctionHouseV2_HistoricPrices_GasSnapshot is NounsAuctionHouseBaseTest { + INounsAuctionHouseV2 auctionHouseV2; + + function setUp() public virtual override { + super.setUp(); + AuctionHouseUpgrader.upgradeAuctionHouse(owner, proxyAdmin, auctionHouseProxy); + auctionHouseV2 = INounsAuctionHouseV2(address(auctionHouse)); + + for (uint256 i = 1; i <= 200; ++i) { + address bidder = makeAddr(vm.toString(i)); + bidAndWinCurrentAuction(bidder, i * 1e18); + } + } + + function bidAndWinCurrentAuction(address bidder, uint256 bid) internal returns (uint256) { + uint128 nounId = auctionHouseV2.auction().nounId; + uint40 endTime = auctionHouseV2.auction().endTime; + vm.deal(bidder, bid); + vm.prank(bidder); + auctionHouseV2.createBid{ value: bid }(nounId); + vm.warp(endTime); + auctionHouseV2.settleCurrentAndCreateNewAuction(); + return block.timestamp; + } + + function test_getSettlements_90() public { + INounsAuctionHouseV2.Settlement[] memory prices = auctionHouseV2.getSettlements(90, false); + assertEq(prices.length, 90); + } + + function test_getPrices_90() public { + uint256[] memory prices = auctionHouseV2.getPrices(90); + assertEq(prices.length, 90); + } + + function test_getSettlements_range_100() public { + INounsAuctionHouseV2.Settlement[] memory settlements = auctionHouseV2.getSettlements(0, 100, false); + assertEq(settlements.length, 100); + } + + function test_warmUp() public { + auctionHouseV2.warmUpSettlementState(0, 1000); + } +} diff --git a/packages/nouns-contracts/test/foundry/NounsAuctionHouseV2.t.sol b/packages/nouns-contracts/test/foundry/NounsAuctionHouseV2.t.sol new file mode 100644 index 0000000000..9eff37bd1a --- /dev/null +++ b/packages/nouns-contracts/test/foundry/NounsAuctionHouseV2.t.sol @@ -0,0 +1,980 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity ^0.8.15; + +import 'forge-std/Test.sol'; +import { DeployUtils } from './helpers/DeployUtils.sol'; +import { AuctionHouseUpgrader } from './helpers/AuctionHouseUpgrader.sol'; +import { NounsAuctionHouseProxy } from '../../contracts/proxies/NounsAuctionHouseProxy.sol'; +import { NounsAuctionHouseProxyAdmin } from '../../contracts/proxies/NounsAuctionHouseProxyAdmin.sol'; +import { NounsAuctionHouse } from '../../contracts/NounsAuctionHouse.sol'; +import { INounsAuctionHouseV2 as IAH } from '../../contracts/interfaces/INounsAuctionHouseV2.sol'; +import { NounsAuctionHouseV2 } from '../../contracts/NounsAuctionHouseV2.sol'; +import { BidderWithGasGriefing } from './helpers/BidderWithGasGriefing.sol'; + +contract NounsAuctionHouseV2TestBase is Test, DeployUtils { + address owner = address(0x1111); + address noundersDAO = address(0x2222); + address minter = address(0x3333); + uint256[] nounIds; + uint32 timestamp = 1702289583; + + NounsAuctionHouseV2 auction; + + function setUp() public virtual { + vm.warp(timestamp); + (NounsAuctionHouseProxy auctionProxy, NounsAuctionHouseProxyAdmin proxyAdmin) = _deployAuctionHouseV1AndToken( + owner, + noundersDAO, + minter + ); + + AuctionHouseUpgrader.upgradeAuctionHouse(owner, proxyAdmin, auctionProxy); + + auction = NounsAuctionHouseV2(address(auctionProxy)); + + vm.prank(owner); + auction.unpause(); + vm.roll(block.number + 1); + } + + function bidAndWinCurrentAuction(address bidder, uint256 bid) internal returns (uint256) { + uint128 nounId = auction.auction().nounId; + vm.deal(bidder, bid); + vm.prank(bidder); + auction.createBid{ value: bid }(nounId); + endAuctionAndSettle(); + return block.timestamp; + } + + function endAuctionAndSettle() internal { + uint40 endTime = auction.auction().endTime; + vm.warp(endTime); + auction.settleCurrentAndCreateNewAuction(); + } + + function bidDontCreateNewAuction(address bidder, uint256 bid) internal returns (uint256) { + uint128 nounId = auction.auction().nounId; + uint40 endTime = auction.auction().endTime; + vm.deal(bidder, bid); + vm.prank(bidder); + auction.createBid{ value: bid }(nounId); + vm.warp(endTime); + return block.timestamp; + } +} + +contract NounsAuctionHouseV2Test is NounsAuctionHouseV2TestBase { + function test_createBid_revertsGivenWrongNounId() public { + uint128 nounId = auction.auction().nounId; + + vm.expectRevert('Noun not up for auction'); + auction.createBid(nounId - 1); + + vm.expectRevert('Noun not up for auction'); + auction.createBid(nounId + 1); + } + + function test_createBid_revertsPastEndTime() public { + uint128 nounId = auction.auction().nounId; + uint40 endTime = auction.auction().endTime; + vm.warp(endTime + 1); + + vm.expectRevert('Auction expired'); + auction.createBid(nounId); + } + + function test_createBid_revertsGivenBidBelowReservePrice() public { + vm.prank(owner); + auction.setReservePrice(1 ether); + + uint128 nounId = auction.auction().nounId; + + vm.expectRevert('Must send at least reservePrice'); + auction.createBid{ value: 0.9 ether }(nounId); + } + + function test_createBid_revertsGivenBidLowerThanMinIncrement() public { + vm.prank(owner); + auction.setMinBidIncrementPercentage(50); + uint128 nounId = auction.auction().nounId; + auction.createBid{ value: 1 ether }(nounId); + + vm.expectRevert('Must send more than last bid by minBidIncrementPercentage amount'); + auction.createBid{ value: 1.49 ether }(nounId); + } + + function test_createBid_refundsPreviousBidder() public { + uint256 nounId = auction.auction().nounId; + address bidder1 = address(0x4444); + address bidder2 = address(0x5555); + + vm.deal(bidder1, 1.1 ether); + vm.prank(bidder1); + auction.createBid{ value: 1.1 ether }(nounId); + + assertEq(bidder1.balance, 0); + + vm.deal(bidder2, 2.2 ether); + vm.prank(bidder2); + auction.createBid{ value: 2.2 ether }(nounId); + + assertEq(bidder1.balance, 1.1 ether); + assertEq(bidder2.balance, 0); + } + + function test_createBid_preventsGasGriefingUponRefunding() public { + BidderWithGasGriefing badBidder = new BidderWithGasGriefing(); + uint256 nounId = auction.auction().nounId; + + badBidder.bid{ value: 1 ether }(auction, nounId); + + address bidder = address(0x4444); + vm.deal(bidder, 1.2 ether); + vm.prank(bidder); + uint256 gasBefore = gasleft(); + auction.createBid{ value: 1.2 ether }(nounId); + uint256 gasDiffWithGriefing = gasBefore - gasleft(); + + address bidder2 = address(0x5555); + vm.deal(bidder2, 2.2 ether); + vm.prank(bidder2); + gasBefore = gasleft(); + auction.createBid{ value: 2.2 ether }(nounId); + uint256 gasDiffNoGriefing = gasBefore - gasleft(); + + // Before the transfer with assembly fix this diff was greater + // closer to 50K + assertLt(gasDiffWithGriefing - gasDiffNoGriefing, 10_000); + } + + function test_settleAuction_revertsWhenAuctionInProgress() public { + vm.expectRevert("Auction hasn't completed"); + auction.settleCurrentAndCreateNewAuction(); + } + + function test_settleAuction_revertsWhenSettled() public { + uint40 endTime = auction.auction().endTime; + vm.warp(endTime + 1); + + vm.prank(owner); + auction.pause(); + auction.settleAuction(); + + vm.expectRevert('Auction has already been settled'); + auction.settleAuction(); + } + + function test_settleAuction_revertsWhenAuctionHasntBegunYet() public { + (NounsAuctionHouseProxy auctionProxy, NounsAuctionHouseProxyAdmin proxyAdmin) = _deployAuctionHouseV1AndToken( + owner, + noundersDAO, + minter + ); + AuctionHouseUpgrader.upgradeAuctionHouse(owner, proxyAdmin, auctionProxy); + auction = NounsAuctionHouseV2(address(auctionProxy)); + + vm.expectRevert("Auction hasn't begun"); + auction.settleAuction(); + } + + function test_settleCurrentAndCreateNewAuction_revertsWhenPaused() public { + uint40 endTime = auction.auction().endTime; + vm.warp(endTime + 1); + + vm.prank(owner); + auction.pause(); + + vm.expectRevert('Pausable: paused'); + auction.settleCurrentAndCreateNewAuction(); + } + + function test_V2Migration_works() public { + (NounsAuctionHouseProxy auctionProxy, NounsAuctionHouseProxyAdmin proxyAdmin) = _deployAuctionHouseV1AndToken( + owner, + noundersDAO, + minter + ); + NounsAuctionHouse auctionV1 = NounsAuctionHouse(address(auctionProxy)); + vm.prank(owner); + auctionV1.unpause(); + vm.roll(block.number + 1); + (uint256 nounId, , uint256 startTime, uint256 endTime, , ) = auctionV1.auction(); + + address payable bidder = payable(address(0x142)); + uint256 amount = 142 ether; + vm.deal(bidder, amount); + vm.prank(bidder); + auctionV1.createBid{ value: amount }(nounId); + + address nounsBefore = address(auctionV1.nouns()); + address wethBefore = address(auctionV1.weth()); + + AuctionHouseUpgrader.upgradeAuctionHouse(owner, proxyAdmin, auctionProxy); + + NounsAuctionHouseV2 auctionV2 = NounsAuctionHouseV2(address(auctionProxy)); + + IAH.AuctionV2View memory auctionV2State = auctionV2.auction(); + + assertEq(auctionV2State.nounId, nounId); + assertEq(auctionV2State.amount, amount); + assertEq(auctionV2State.startTime, startTime); + assertEq(auctionV2State.endTime, endTime); + assertEq(auctionV2State.bidder, bidder); + assertEq(auctionV2State.settled, false); + + assertEq(address(auctionV2.nouns()), nounsBefore); + assertEq(address(auctionV2.weth()), wethBefore); + assertEq(auctionV2.timeBuffer(), AUCTION_TIME_BUFFER); + assertEq(auctionV2.reservePrice(), AUCTION_RESERVE_PRICE); + assertEq(auctionV2.minBidIncrementPercentage(), AUCTION_MIN_BID_INCREMENT_PRCT); + assertEq(auctionV2.duration(), AUCTION_DURATION); + assertEq(auctionV2.paused(), false); + assertEq(auctionV2.owner(), owner); + } + + function test_V2Migration_copiesPausedWhenTrue() public { + (NounsAuctionHouseProxy auctionProxy, NounsAuctionHouseProxyAdmin proxyAdmin) = _deployAuctionHouseV1AndToken( + owner, + noundersDAO, + minter + ); + NounsAuctionHouse auctionV1 = NounsAuctionHouse(address(auctionProxy)); + vm.prank(owner); + auctionV1.unpause(); + vm.roll(block.number + 1); + (uint256 nounId, , , , , ) = auctionV1.auction(); + + address payable bidder = payable(address(0x142)); + uint256 amount = 142 ether; + vm.deal(bidder, amount); + vm.prank(bidder); + auctionV1.createBid{ value: amount }(nounId); + + vm.prank(owner); + auctionV1.pause(); + + AuctionHouseUpgrader.upgradeAuctionHouse(owner, proxyAdmin, auctionProxy); + + NounsAuctionHouseV2 auctionV2 = NounsAuctionHouseV2(address(auctionProxy)); + assertEq(auctionV2.paused(), true); + } + + function test_auctionGetter_compatibleWithV1() public { + address bidder = address(0x4242); + vm.deal(bidder, 1.1 ether); + vm.prank(bidder); + auction.createBid{ value: 1.1 ether }(1); + + NounsAuctionHouse auctionV1 = NounsAuctionHouse(address(auction)); + + IAH.AuctionV2View memory auctionV2 = auction.auction(); + + ( + uint256 nounIdV1, + uint256 amountV1, + uint256 startTimeV1, + uint256 endTimeV1, + address payable bidderV1, + bool settledV1 + ) = auctionV1.auction(); + + assertEq(auctionV2.nounId, nounIdV1); + assertEq(auctionV2.amount, amountV1); + assertEq(auctionV2.startTime, startTimeV1); + assertEq(auctionV2.endTime, endTimeV1); + assertEq(auctionV2.bidder, bidderV1); + assertEq(auctionV2.settled, settledV1); + } + + function test_setMinBidIncrementPercentage_givenNonOwnerSender_reverts() public { + vm.expectRevert('Ownable: caller is not the owner'); + auction.setMinBidIncrementPercentage(42); + } + + function test_setMinBidIncrementPercentage_givenZero_reverts() public { + vm.prank(auction.owner()); + vm.expectRevert('must be greater than zero'); + auction.setMinBidIncrementPercentage(0); + } + + function test_setMinBidIncrementPercentage_givenNonZeroInput_works() public { + assertNotEq(auction.minBidIncrementPercentage(), 42); + + vm.prank(auction.owner()); + auction.setMinBidIncrementPercentage(42); + + assertEq(auction.minBidIncrementPercentage(), 42); + } +} + +abstract contract NoracleBaseTest is NounsAuctionHouseV2TestBase { + uint256[] expectedPrices; + IAH.Settlement[] expectedSettlements; + address bidder = makeAddr('bidder'); + + function assertEq(IAH.Settlement[] memory s1, IAH.Settlement[] memory s2) internal { + assertEq(s1.length, s2.length, 'wrong length'); + for (uint256 i; i < s1.length; i++) { + assertEq(s1[i].blockTimestamp, s2[i].blockTimestamp, 'wrong timestamp'); + assertEq(s1[i].amount, s2[i].amount, 'wrong amount'); + assertEq(s1[i].winner, s2[i].winner, 'wrong winner'); + assertEq(s1[i].nounId, s2[i].nounId, 'wrong noun id'); + } + } + + function reverse(IAH.Settlement[] storage s) internal view returns (IAH.Settlement[] memory) { + IAH.Settlement[] memory s2 = new IAH.Settlement[](s.length); + for (uint256 i = 0; i < s.length; ++i) { + s2[s2.length - i - 1] = s[i]; + } + return s2; + } +} + +contract NoracleTestOneAuctionSettledStateTest is NoracleBaseTest { + IAH.Settlement nounId1Settlement; + + function setUp() public override { + super.setUp(); + bidAndWinCurrentAuction(bidder, 1 ether); + + nounId1Settlement = IAH.Settlement({ + blockTimestamp: uint32(block.timestamp), + amount: 1 ether, + winner: bidder, + nounId: 1, + clientId: 0 + }); + } + + function test_prices() public { + expectedPrices = [1 ether]; + + assertEq(auction.getPrices(1), expectedPrices); + } + + function test_prices_reverts_ifRequestMoreThanAvailableHistory() public { + vm.expectRevert('Not enough history'); + auction.getPrices(2); + } + + function test_getSettlements_skipFalse_1() public { + IAH.Settlement[] memory settlements = auction.getSettlements(1, false); + + expectedSettlements.push(nounId1Settlement); + assertEq(settlements, expectedSettlements); + } + + function test_getSettlementsRange_skipFalse_1() public { + IAH.Settlement[] memory settlements = auction.getSettlements(1, 2, false); + expectedSettlements.push(nounId1Settlement); + assertEq(settlements, expectedSettlements); + } + + function test_getSettlementsFromIdtoTimestamp_skipFalse_1() public { + IAH.Settlement[] memory settlements = auction.getSettlementsFromIdtoTimestamp(1, block.timestamp, false); + expectedSettlements.push(nounId1Settlement); + assertEq(settlements, expectedSettlements); + } + + function test_getSettlements_skipFalse_returnsRawNounderNouns() public { + IAH.Settlement[] memory settlements = auction.getSettlements(2, false); + + expectedSettlements.push(nounId1Settlement); + expectedSettlements.push( + IAH.Settlement({ blockTimestamp: 0, amount: 0, winner: address(0), nounId: 0, clientId: 0 }) + ); + assertEq(settlements, expectedSettlements); + } + + function test_getSettlementsRange_skipFalse_returnsRawNounderNouns() public { + IAH.Settlement[] memory settlements = auction.getSettlements(0, 2, false); + expectedSettlements.push( + IAH.Settlement({ blockTimestamp: 0, amount: 0, winner: address(0), nounId: 0, clientId: 0 }) + ); + expectedSettlements.push(nounId1Settlement); + assertEq(settlements, expectedSettlements); + } + + function test_getSettlementsFromIdtoTimestamp_skipFalse_returnsRawNounderNouns() public { + IAH.Settlement[] memory settlements = auction.getSettlementsFromIdtoTimestamp(0, block.timestamp, false); + expectedSettlements.push( + IAH.Settlement({ blockTimestamp: 0, amount: 0, winner: address(0), nounId: 0, clientId: 0 }) + ); + expectedSettlements.push(nounId1Settlement); + assertEq(settlements, expectedSettlements); + } + + function test_getSettlementsFormIdToTimestamp_skipFalse_stopsAtEndTimestamp() public { + IAH.Settlement[] memory settlements = auction.getSettlementsFromIdtoTimestamp(0, block.timestamp - 1, false); + expectedSettlements.push( + IAH.Settlement({ blockTimestamp: 0, amount: 0, winner: address(0), nounId: 0, clientId: 0 }) + ); + assertEq(settlements, expectedSettlements); + } + + function test_getSettlementsFormIdToTimestamp_skipFalse_startIdInTheFuture_reverts() public { + vm.expectRevert('startId too large'); + auction.getSettlementsFromIdtoTimestamp(3, block.timestamp, false); + } + + function test_getSettlementsRange_skipFalse_returnsEmptyData() public { + IAH.Settlement[] memory settlements = auction.getSettlements(0, 3, false); + expectedSettlements.push( + IAH.Settlement({ blockTimestamp: 0, amount: 0, winner: address(0), nounId: 0, clientId: 0 }) + ); + expectedSettlements.push(nounId1Settlement); + expectedSettlements.push( + IAH.Settlement({ blockTimestamp: 0, amount: 0, winner: address(0), nounId: 2, clientId: 0 }) + ); + assertEq(settlements, expectedSettlements); + } + + function test_getSettlements_skipFalse_returnsLessResultsIfReachedNounZero() public { + IAH.Settlement[] memory settlements = auction.getSettlements(3, false); + + expectedSettlements.push(nounId1Settlement); + expectedSettlements.push( + IAH.Settlement({ blockTimestamp: 0, amount: 0, winner: address(0), nounId: 0, clientId: 0 }) + ); + assertEq(settlements, expectedSettlements); + } + + function test_getSettlements_skipTrue_skipsNounderNouns() public { + IAH.Settlement[] memory settlements = auction.getSettlements(2, true); + + expectedSettlements.push(nounId1Settlement); + assertEq(settlements, expectedSettlements); + } + + function test_getSettlementsRange_skipTrue_skipsNounderNouns() public { + IAH.Settlement[] memory settlements = auction.getSettlements(0, 2, true); + expectedSettlements.push(nounId1Settlement); + assertEq(settlements, expectedSettlements); + } + + function test_getSettlementsFromIdToTimestamp_skipTrue_skipsNonderNouns() public { + IAH.Settlement[] memory settlements = auction.getSettlementsFromIdtoTimestamp(0, block.timestamp, true); + expectedSettlements.push(nounId1Settlement); + assertEq(settlements, expectedSettlements); + } + + function test_getSettlementsRange_skipTrue_skipsEmptyData() public { + IAH.Settlement[] memory settlements = auction.getSettlements(0, 4, true); + expectedSettlements.push(nounId1Settlement); + assertEq(settlements, expectedSettlements); + } + + function test_prices_preserves10DecimalsUnderUint64MaxValue() public { + // amount is uint64; maxValue - 1 = 18446744073709551615 + // at 10 decimal points it's 1844674407.3709551615 + bidAndWinCurrentAuction(makeAddr('bidder'), 1844674407.3709551615999999 ether); + + IAH.Settlement[] memory settlements = auction.getSettlements(1, true); + + assertEq(settlements.length, 1); + assertEq(settlements[0].nounId, 2); + assertEq(settlements[0].amount, 1844674407.3709551615 ether); + assertEq(settlements[0].winner, makeAddr('bidder')); + + uint256[] memory prices = auction.getPrices(1); + assertEq(prices[0], 1844674407.3709551615 ether); + } + + function test_prices_overflowsGracefullyOverUint64MaxValue() public { + bidAndWinCurrentAuction(makeAddr('bidder'), 1844674407.3709551617 ether); + + IAH.Settlement[] memory settlements = auction.getSettlements(1, false); + + assertEq(settlements.length, 1); + assertEq(settlements[0].nounId, 2); + assertEq(settlements[0].amount, 1 * 1e8); + assertEq(settlements[0].winner, makeAddr('bidder')); + + uint256[] memory prices = auction.getPrices(1); + assertEq(prices[0], 1 * 1e8); + } +} + +contract NoracleTestManyAuctionsSettledStateTest is NoracleBaseTest { + function setUp() public override { + super.setUp(); + for (uint256 i = 1; i <= 20; ++i) { + address bidder = makeAddr(vm.toString(i)); + bidAndWinCurrentAuction(bidder, i * 1e18); + } + } + + function test_getSettlements_skipsNounderNouns() public { + IAH.Settlement[] memory settlements = auction.getSettlements(20, true); + assertEq(settlements[0].nounId, 22); + assertEq(settlements[1].nounId, 21); + assertEq(settlements[2].nounId, 19); + assertEq(settlements[10].nounId, 11); + assertEq(settlements[11].nounId, 9); + assertEq(settlements[19].nounId, 1); + + assertEq(settlements[0].amount, 20 ether); + assertEq(settlements[1].amount, 19 ether); + assertEq(settlements[2].amount, 18 ether); + assertEq(settlements[10].amount, 10 ether); + assertEq(settlements[11].amount, 9 ether); + assertEq(settlements[19].amount, 1 ether); + } + + function test_getPrices_skipsNounderNouns() public { + uint256[] memory prices = auction.getPrices(20); + // prettier-ignore + expectedPrices = [20e18, 19e18, 18e18, 17e18, 16e18, 15e18, 14e18, 13e18, 12e18, 11e18, + 10e18, 9e18, 8e18, 7e18, 6e18, 5e18, 4e18, 3e18, 2e18, 1e18]; + assertEq(prices, expectedPrices); + } + + function test_getSettlementRange_limitsToRange() public { + IAH.Settlement[] memory settlements = auction.getSettlements(3, 8, true); + assertEq(settlements.length, 5); + assertEq(settlements[0].nounId, 3); + assertEq(settlements[1].nounId, 4); + assertEq(settlements[2].nounId, 5); + assertEq(settlements[3].nounId, 6); + assertEq(settlements[4].nounId, 7); + } + + function test_getSettlementFromIdToTimestamp_limitsToTimestamp() public { + // get the timestamp of id 7 + uint256 endTimestamp = auction.getSettlements(7, 8, true)[0].blockTimestamp; + + IAH.Settlement[] memory settlements = auction.getSettlementsFromIdtoTimestamp(3, endTimestamp, true); + assertEq(settlements.length, 5); + assertEq(settlements[0].nounId, 3); + assertEq(settlements[1].nounId, 4); + assertEq(settlements[2].nounId, 5); + assertEq(settlements[3].nounId, 6); + assertEq(settlements[4].nounId, 7); + } +} + +contract NoracleTest_GapInHistoricPricesTest is NoracleBaseTest { + function setUp() public override { + super.setUp(); + + bidAndWinCurrentAuction(bidder, 1 ether); // settle noun 1 + + vm.startPrank(address(auction)); + for (uint256 i = 0; i < 3; ++i) { + auction.nouns().mint(); // mint nouns 3,4,5 + } + vm.stopPrank(); + + bidAndWinCurrentAuction(bidder, 2 ether); // settle noun 2 + bidAndWinCurrentAuction(bidder, 6 ether); // settle noun 6 + } + + function test_prices_revertsIfEmptyAuctionData() public { + // this works + auction.getPrices(1); + + // this doesn't + vm.expectRevert('Missing data'); + auction.getPrices(2); + } + + function test_getSettlements_skipTrue_skipsEmptyData() public { + IAH.Settlement[] memory settlements = auction.getSettlements(20, true); + + uint256 ts = block.timestamp; + expectedSettlements.push( + IAH.Settlement({ blockTimestamp: uint32(ts), amount: 6 ether, winner: bidder, nounId: 6, clientId: 0 }) + ); + expectedSettlements.push( + IAH.Settlement({ + blockTimestamp: uint32(ts - 24 hours), + amount: 2 ether, + winner: bidder, + nounId: 2, + clientId: 0 + }) + ); + expectedSettlements.push( + IAH.Settlement({ + blockTimestamp: uint32(ts - 48 hours), + amount: 1 ether, + winner: bidder, + nounId: 1, + clientId: 0 + }) + ); + assertEq(settlements, expectedSettlements); + + IAH.Settlement[] memory settlements2 = auction.getSettlements(0, 20, true); + assertEq(settlements2, reverse(expectedSettlements)); + + IAH.Settlement[] memory settlements3 = auction.getSettlementsFromIdtoTimestamp(0, block.timestamp, true); + assertEq(settlements3, reverse(expectedSettlements)); + } + + function test_getSettlements_skipFalse() public { + IAH.Settlement[] memory settlements = auction.getSettlements(20, false); + + uint256 ts = block.timestamp; + expectedSettlements.push( + IAH.Settlement({ blockTimestamp: uint32(ts), amount: 6 ether, winner: bidder, nounId: 6, clientId: 0 }) + ); + expectedSettlements.push( + IAH.Settlement({ blockTimestamp: 0, amount: 0, winner: address(0), nounId: 5, clientId: 0 }) + ); + expectedSettlements.push( + IAH.Settlement({ blockTimestamp: 0, amount: 0, winner: address(0), nounId: 4, clientId: 0 }) + ); + expectedSettlements.push( + IAH.Settlement({ blockTimestamp: 0, amount: 0, winner: address(0), nounId: 3, clientId: 0 }) + ); + expectedSettlements.push( + IAH.Settlement({ + blockTimestamp: uint32(ts - 24 hours), + amount: 2 ether, + winner: bidder, + nounId: 2, + clientId: 0 + }) + ); + expectedSettlements.push( + IAH.Settlement({ + blockTimestamp: uint32(ts - 48 hours), + amount: 1 ether, + winner: bidder, + nounId: 1, + clientId: 0 + }) + ); + expectedSettlements.push( + IAH.Settlement({ blockTimestamp: 0, amount: 0, winner: address(0), nounId: 0, clientId: 0 }) + ); + assertEq(settlements, expectedSettlements); + + IAH.Settlement[] memory settlements2 = auction.getSettlements(0, 7, false); + assertEq(settlements2, reverse(expectedSettlements)); + + IAH.Settlement[] memory settlements3 = auction.getSettlementsFromIdtoTimestamp(0, block.timestamp, false); + assertEq(settlements3, reverse(expectedSettlements)); + } +} + +contract NoracleTest_GapInHistoricPrices_AfterWarmUp_Test is NoracleBaseTest { + function setUp() public override { + super.setUp(); + + auction.warmUpSettlementState(0, 7); + + bidAndWinCurrentAuction(bidder, 1 ether); // settle noun 1 + + vm.startPrank(address(auction)); + for (uint256 i = 0; i < 3; ++i) { + auction.nouns().mint(); // mint nouns 3,4,5 + } + vm.stopPrank(); + + bidAndWinCurrentAuction(bidder, 2 ether); // settle noun 2 + bidAndWinCurrentAuction(bidder, 6 ether); // settle noun 6 + } + + function test_prices_revertsIfEmptyAuctionData() public { + // this works + auction.getPrices(1); + + // this doesn't + vm.expectRevert('Missing data'); + auction.getPrices(2); + } + + function test_getSettlements_skipTrue_skipsEmptyData() public { + IAH.Settlement[] memory settlements = auction.getSettlements(20, true); + + uint256 ts = block.timestamp; + expectedSettlements.push( + IAH.Settlement({ blockTimestamp: uint32(ts), amount: 6 ether, winner: bidder, nounId: 6, clientId: 0 }) + ); + expectedSettlements.push( + IAH.Settlement({ + blockTimestamp: uint32(ts - 24 hours), + amount: 2 ether, + winner: bidder, + nounId: 2, + clientId: 0 + }) + ); + expectedSettlements.push( + IAH.Settlement({ + blockTimestamp: uint32(ts - 48 hours), + amount: 1 ether, + winner: bidder, + nounId: 1, + clientId: 0 + }) + ); + assertEq(settlements, expectedSettlements); + + IAH.Settlement[] memory settlements2 = auction.getSettlements(0, 20, true); + assertEq(settlements2, reverse(expectedSettlements)); + + IAH.Settlement[] memory settlements3 = auction.getSettlementsFromIdtoTimestamp(0, block.timestamp, true); + assertEq(settlements3, reverse(expectedSettlements)); + } + + function test_getSettlements_skipFalse() public { + IAH.Settlement[] memory settlements = auction.getSettlements(20, false); + + uint256 ts = block.timestamp; + expectedSettlements.push( + IAH.Settlement({ blockTimestamp: uint32(ts), amount: 6 ether, winner: bidder, nounId: 6, clientId: 0 }) + ); + expectedSettlements.push( + IAH.Settlement({ blockTimestamp: 1, amount: 0, winner: address(0), nounId: 5, clientId: 0 }) + ); + expectedSettlements.push( + IAH.Settlement({ blockTimestamp: 1, amount: 0, winner: address(0), nounId: 4, clientId: 0 }) + ); + expectedSettlements.push( + IAH.Settlement({ blockTimestamp: 1, amount: 0, winner: address(0), nounId: 3, clientId: 0 }) + ); + expectedSettlements.push( + IAH.Settlement({ + blockTimestamp: uint32(ts - 24 hours), + amount: 2 ether, + winner: bidder, + nounId: 2, + clientId: 0 + }) + ); + expectedSettlements.push( + IAH.Settlement({ + blockTimestamp: uint32(ts - 48 hours), + amount: 1 ether, + winner: bidder, + nounId: 1, + clientId: 0 + }) + ); + + // timestamp remains 0 here because it's a Nounder reward ID that does not get warmed up. + expectedSettlements.push( + IAH.Settlement({ blockTimestamp: 0, amount: 0, winner: address(0), nounId: 0, clientId: 0 }) + ); + assertEq(settlements, expectedSettlements); + + IAH.Settlement[] memory settlements2 = auction.getSettlements(0, 7, false); + assertEq(settlements2, reverse(expectedSettlements)); + + IAH.Settlement[] memory settlements3 = auction.getSettlementsFromIdtoTimestamp(0, block.timestamp, false); + assertEq(settlements3, reverse(expectedSettlements)); + } +} + +contract NoracleTest_AuctionWithNoBids is NoracleBaseTest { + function setUp() public override { + super.setUp(); + + bidAndWinCurrentAuction(bidder, 1 ether); // settle noun 1 + endAuctionAndSettle(); // no winner for noun 2 + bidAndWinCurrentAuction(bidder, 3 ether); // settle noun 3 + } + + function test_getPrices_skipsAuctionsWithNotBids() public { + uint256[] memory prices = auction.getPrices(2); + expectedPrices = [3 ether, 1 ether]; + assertEq(prices, expectedPrices); + } + + function test_getSettlements_skipFalse() public { + IAH.Settlement[] memory settlements = auction.getSettlements(20, false); + + uint256 ts = block.timestamp; + expectedSettlements.push( + IAH.Settlement({ blockTimestamp: uint32(ts), amount: 3 ether, winner: bidder, nounId: 3, clientId: 0 }) + ); + expectedSettlements.push( + IAH.Settlement({ + blockTimestamp: uint32(ts - 24 hours), + amount: 0, + winner: address(0), + nounId: 2, + clientId: 0 + }) + ); + expectedSettlements.push( + IAH.Settlement({ + blockTimestamp: uint32(ts - 48 hours), + amount: 1 ether, + winner: bidder, + nounId: 1, + clientId: 0 + }) + ); + expectedSettlements.push( + IAH.Settlement({ blockTimestamp: 0, amount: 0, winner: address(0), nounId: 0, clientId: 0 }) + ); + assertEq(settlements, expectedSettlements); + + IAH.Settlement[] memory settlements2 = auction.getSettlements(0, 4, false); + assertEq(settlements2, reverse(expectedSettlements)); + + IAH.Settlement[] memory settlements3 = auction.getSettlementsFromIdtoTimestamp(0, block.timestamp, false); + assertEq(settlements3, reverse(expectedSettlements)); + } + + function test_getSettlements_skipTrue_includesAuctionsWithNoBids() public { + IAH.Settlement[] memory settlements = auction.getSettlements(20, true); + + uint256 ts = block.timestamp; + expectedSettlements.push( + IAH.Settlement({ blockTimestamp: uint32(ts), amount: 3 ether, winner: bidder, nounId: 3, clientId: 0 }) + ); + expectedSettlements.push( + IAH.Settlement({ + blockTimestamp: uint32(ts - 24 hours), + amount: 0, + winner: address(0), + nounId: 2, + clientId: 0 + }) + ); + expectedSettlements.push( + IAH.Settlement({ + blockTimestamp: uint32(ts - 48 hours), + amount: 1 ether, + winner: bidder, + nounId: 1, + clientId: 0 + }) + ); + assertEq(settlements, expectedSettlements); + + IAH.Settlement[] memory settlements2 = auction.getSettlements(0, 20, true); + assertEq(settlements2, reverse(expectedSettlements)); + + IAH.Settlement[] memory settlements3 = auction.getSettlementsFromIdtoTimestamp(0, block.timestamp, true); + assertEq(settlements3, reverse(expectedSettlements)); + } +} + +contract NoracleTest_NoActiveAuction is NoracleBaseTest { + function setUp() public override { + super.setUp(); + + bidAndWinCurrentAuction(makeAddr('bidder'), 1 ether); + bidDontCreateNewAuction(makeAddr('bidder 2'), 2 ether); + + vm.prank(auction.owner()); + auction.pause(); + auction.settleAuction(); + } + + function test_prices_includesLastNoun() public { + expectedPrices = [2 ether, 1 ether]; + uint256[] memory prices = auction.getPrices(2); + assertEq(prices, expectedPrices); + } + + function test_getSettlements_includesLastNoun() public { + IAH.Settlement[] memory settlements = auction.getSettlements(20, true); + + uint256 ts = block.timestamp; + expectedSettlements.push( + IAH.Settlement({ + blockTimestamp: uint32(ts), + amount: 2 ether, + winner: makeAddr('bidder 2'), + nounId: 2, + clientId: 0 + }) + ); + expectedSettlements.push( + IAH.Settlement({ + blockTimestamp: uint32(ts - 24 hours), + amount: 1 ether, + winner: makeAddr('bidder'), + nounId: 1, + clientId: 0 + }) + ); + assertEq(settlements, expectedSettlements); + + IAH.Settlement[] memory settlements2 = auction.getSettlements(0, 20, true); + assertEq(settlements2, reverse(expectedSettlements)); + + IAH.Settlement[] memory settlements3 = auction.getSettlementsFromIdtoTimestamp(0, block.timestamp, true); + assertEq(settlements3, reverse(expectedSettlements)); + } +} + +contract NounsAuctionHouseV2_setPricesTest is NoracleBaseTest { + function test_setPrices_revertsForNonOwner() public { + IAH.SettlementNoClientId[] memory settlements = new IAH.SettlementNoClientId[](1); + settlements[0] = IAH.SettlementNoClientId({ + blockTimestamp: uint32(block.timestamp), + amount: 42 ether, + winner: makeAddr('winner'), + nounId: 3 + }); + + vm.expectRevert('Ownable: caller is not the owner'); + auction.setPrices(settlements); + } + + function test_setPrices_worksForOwner() public { + IAH.SettlementNoClientId[] memory settlements = new IAH.SettlementNoClientId[](20); + + uint256 nounId = 0; + for (uint256 i = 0; i < 20; ++i) { + // skip Nouners + if (nounId <= 1820 && nounId % 10 == 0) { + nounId++; + } + + uint256 price = nounId * 1 ether; + + settlements[i] = IAH.SettlementNoClientId({ + blockTimestamp: 100000000 + uint32(nounId), + amount: price, + winner: makeAddr(vm.toString(nounId)), + nounId: nounId + }); + + nounId++; + } + + vm.prank(auction.owner()); + auction.setPrices(settlements); + + IAH.Settlement[] memory actualSettlements = auction.getSettlements(0, 23, true); + assertEq(actualSettlements.length, 20); + for (uint256 i = 0; i < 20; ++i) { + assertEq(settlements[i].blockTimestamp, actualSettlements[i].blockTimestamp); + assertEq(settlements[i].amount, actualSettlements[i].amount); + assertEq(settlements[i].winner, actualSettlements[i].winner); + assertEq(settlements[i].nounId, actualSettlements[i].nounId); + } + } +} + +contract NounsAuctionHouseV2_OwnerFunctionsTest is NounsAuctionHouseV2TestBase { + function test_setTimeBuffer_revertsForNonOwner() public { + vm.expectRevert('Ownable: caller is not the owner'); + auction.setTimeBuffer(1 days); + } + + function test_setTimeBuffer_revertsGivenValueAboveMax() public { + vm.prank(auction.owner()); + vm.expectRevert('timeBuffer too large'); + auction.setTimeBuffer(1 days + 1); + } + + function test_setTimeBuffer_worksForOwner() public { + assertEq(auction.timeBuffer(), 5 minutes); + + vm.prank(auction.owner()); + auction.setTimeBuffer(1 days); + + assertEq(auction.timeBuffer(), 1 days); + } +} diff --git a/packages/nouns-contracts/test/foundry/NounsDAOData.t.sol b/packages/nouns-contracts/test/foundry/NounsDAOData.t.sol index 615852358f..69d9497e3c 100644 --- a/packages/nouns-contracts/test/foundry/NounsDAOData.t.sol +++ b/packages/nouns-contracts/test/foundry/NounsDAOData.t.sol @@ -1,25 +1,35 @@ // SPDX-License-Identifier: GPL-3.0 -pragma solidity ^0.8.15; +pragma solidity ^0.8.19; import 'forge-std/Test.sol'; +import { DeployUtilsV3 } from './helpers/DeployUtilsV3.sol'; +import { AuctionHelpers } from './helpers/AuctionHelpers.sol'; +import { INounsDAOLogic } from '../../contracts/interfaces/INounsDAOLogic.sol'; +import { NounsTokenLike, NounsDAOTypes } from '../../contracts/governance/NounsDAOInterfaces.sol'; +import { INounsAuctionHouse } from '../../contracts/interfaces/INounsAuctionHouse.sol'; import { NounsDAOData } from '../../contracts/governance/data/NounsDAOData.sol'; import { NounsDAODataEvents } from '../../contracts/governance/data/NounsDAODataEvents.sol'; import { NounsDAODataProxy } from '../../contracts/governance/data/NounsDAODataProxy.sol'; -import { NounsTokenLikeMock } from './helpers/NounsTokenLikeMock.sol'; -import { NounsDAOV3Proposals } from '../../contracts/governance/NounsDAOV3Proposals.sol'; +import { NounsDAOProposals } from '../../contracts/governance/NounsDAOProposals.sol'; import { SigUtils } from './helpers/SigUtils.sol'; -contract NounsDAODataTest is Test, SigUtils, NounsDAODataEvents { - NounsTokenLikeMock tokenLikeMock; +abstract contract NounsDAODataBaseTest is DeployUtilsV3, SigUtils, NounsDAODataEvents, AuctionHelpers { NounsDAODataProxy proxy; NounsDAOData data; address dataAdmin = makeAddr('data admin'); - address nounsDao = makeAddr('nouns dao'); + INounsDAOLogic nounsDao; + INounsAuctionHouse auction; address feeRecipient = makeAddr('fee recipient'); + address otherProposer = makeAddr('other proposer'); + address notNouner = makeAddr('not nouner'); - function setUp() public { - tokenLikeMock = new NounsTokenLikeMock(); - NounsDAOData logic = new NounsDAOData(address(tokenLikeMock), nounsDao); + function setUp() public virtual { + nounsDao = INounsDAOLogic(address(_deployDAOV3())); + auction = INounsAuctionHouse(nounsDao.nouns().minter()); + vm.prank(address(nounsDao.timelock())); + auction.unpause(); + + NounsDAOData logic = new NounsDAOData(address(nounsDao.nouns()), address(nounsDao)); bytes memory initCallData = abi.encodeWithSignature( 'initialize(address,uint256,uint256,address)', @@ -30,16 +40,50 @@ contract NounsDAODataTest is Test, SigUtils, NounsDAODataEvents { ); proxy = new NounsDAODataProxy(address(logic), initCallData); - data = NounsDAOData(address(proxy)); + bidAndSettleAuction(auction, address(this)); + bidAndSettleAuction(auction, otherProposer); + vm.roll(block.number + 1); } + function createTxs( + address target, + uint256 value, + string memory signature, + bytes memory callData + ) internal pure returns (NounsDAOProposals.ProposalTxs memory) { + return createTxs(1, target, value, signature, callData); + } + + function createTxs( + uint256 count, + address target, + uint256 value, + string memory signature, + bytes memory callData + ) internal pure returns (NounsDAOProposals.ProposalTxs memory) { + address[] memory targets = new address[](count); + uint256[] memory values = new uint256[](count); + string[] memory signatures = new string[](count); + bytes[] memory calldatas = new bytes[](count); + for (uint256 i = 0; i < count; i++) { + targets[i] = target; + values[i] = value; + signatures[i] = signature; + calldatas[i] = callData; + } + return NounsDAOProposals.ProposalTxs(targets, values, signatures, calldatas); + } +} + +contract NounsDAOData_CreateCandidateTest is NounsDAODataBaseTest { function test_createProposalCandidate_revertsForNonNounerAndNoPayment() public { - NounsDAOV3Proposals.ProposalTxs memory txs = createTxs(address(0), 0, 'some signature', 'some data'); + NounsDAOProposals.ProposalTxs memory txs = createTxs(address(0), 0, 'some signature', 'some data'); vm.expectRevert(abi.encodeWithSelector(NounsDAOData.MustBeNounerOrPaySufficientFee.selector)); + vm.prank(notNouner); data.createProposalCandidate(txs.targets, txs.values, txs.signatures, txs.calldatas, 'description', 'slug', 0); } @@ -52,9 +96,9 @@ contract NounsDAODataTest is Test, SigUtils, NounsDAODataEvents { uint256 value = 300; string memory signature = 'some signature'; bytes memory callData = 'some data'; - NounsDAOV3Proposals.ProposalTxs memory txs = createTxs(target, value, signature, callData); + NounsDAOProposals.ProposalTxs memory txs = createTxs(target, value, signature, callData); - bytes memory encodedProp = NounsDAOV3Proposals.calcProposalEncodeData(proposer, txs, description); + bytes memory encodedProp = NounsDAOProposals.calcProposalEncodeData(proposer, txs, description); bytes32 digest = keccak256(encodedProp); assertEq(digest, 0xcf95b7d08d761ff0bf1223220f45b79baffbce6c8bcceb8df5399cbc6d22c40d); @@ -72,8 +116,8 @@ contract NounsDAODataTest is Test, SigUtils, NounsDAODataEvents { calldatas[0] = callData; calldatas[1] = hex'aabbccdd'; - txs = NounsDAOV3Proposals.ProposalTxs(targets, values, signatures, calldatas); - encodedProp = NounsDAOV3Proposals.calcProposalEncodeData(proposer, txs, description); + txs = NounsDAOProposals.ProposalTxs(targets, values, signatures, calldatas); + encodedProp = NounsDAOProposals.calcProposalEncodeData(proposer, txs, description); digest = keccak256(encodedProp); assertEq(digest, 0x5d6f3b870407fff8109c6c9469173eef879d0d2eaf3de0fb5770b7f48f760101); @@ -88,9 +132,7 @@ contract NounsDAODataTest is Test, SigUtils, NounsDAODataEvents { function test_createProposalCandidate_worksForNouner() public { string memory description = 'some description'; string memory slug = 'some slug'; - NounsDAOV3Proposals.ProposalTxs memory txs = createTxs(address(0), 0, 'some signature', 'some data'); - - tokenLikeMock.setPriorVotes(address(this), block.number - 1, 1); + NounsDAOProposals.ProposalTxs memory txs = createTxs(address(0), 0, 'some signature', 'some data'); vm.expectEmit(true, true, true, true); emit ProposalCandidateCreated( @@ -102,7 +144,7 @@ contract NounsDAODataTest is Test, SigUtils, NounsDAODataEvents { description, slug, 0, - keccak256(NounsDAOV3Proposals.calcProposalEncodeData(address(this), txs, description)) + keccak256(NounsDAOProposals.calcProposalEncodeData(address(this), txs, description)) ); data.createProposalCandidate(txs.targets, txs.values, txs.signatures, txs.calldatas, description, slug, 0); @@ -111,7 +153,7 @@ contract NounsDAODataTest is Test, SigUtils, NounsDAODataEvents { function test_createProposalCandidate_worksForNonNounerWithEnoughPayment() public { string memory description = 'some description'; string memory slug = 'some slug'; - NounsDAOV3Proposals.ProposalTxs memory txs = createTxs(address(0), 0, 'some signature', 'some data'); + NounsDAOProposals.ProposalTxs memory txs = createTxs(address(0), 0, 'some signature', 'some data'); uint256 recipientBalanceBefore = feeRecipient.balance; vm.expectEmit(true, true, true, true); @@ -124,7 +166,7 @@ contract NounsDAODataTest is Test, SigUtils, NounsDAODataEvents { description, slug, 0, - keccak256(NounsDAOV3Proposals.calcProposalEncodeData(address(this), txs, description)) + keccak256(NounsDAOProposals.calcProposalEncodeData(address(this), txs, description)) ); data.createProposalCandidate{ value: data.createCandidateCost() }( @@ -143,7 +185,7 @@ contract NounsDAODataTest is Test, SigUtils, NounsDAODataEvents { function test_createProposalCandidate_givenFeeRecipientZero_accumelatesETHFee() public { string memory description = 'some description'; string memory slug = 'some slug'; - NounsDAOV3Proposals.ProposalTxs memory txs = createTxs(address(0), 0, 'some signature', 'some data'); + NounsDAOProposals.ProposalTxs memory txs = createTxs(address(0), 0, 'some signature', 'some data'); vm.prank(dataAdmin); data.setFeeRecipient(payable(address(0))); @@ -160,7 +202,7 @@ contract NounsDAODataTest is Test, SigUtils, NounsDAODataEvents { description, slug, 0, - keccak256(NounsDAOV3Proposals.calcProposalEncodeData(address(this), txs, description)) + keccak256(NounsDAOProposals.calcProposalEncodeData(address(this), txs, description)) ); data.createProposalCandidate{ value: data.createCandidateCost() }( @@ -182,7 +224,7 @@ contract NounsDAODataTest is Test, SigUtils, NounsDAODataEvents { string memory description = 'some description'; string memory slug = 'some slug'; - NounsDAOV3Proposals.ProposalTxs memory txs = createTxs(address(0), 0, 'some signature', 'some data'); + NounsDAOProposals.ProposalTxs memory txs = createTxs(address(0), 0, 'some signature', 'some data'); vm.expectEmit(true, true, true, true); emit ProposalCandidateCreated( @@ -194,7 +236,7 @@ contract NounsDAODataTest is Test, SigUtils, NounsDAODataEvents { description, slug, 0, - keccak256(NounsDAOV3Proposals.calcProposalEncodeData(address(this), txs, description)) + keccak256(NounsDAOProposals.calcProposalEncodeData(address(this), txs, description)) ); data.createProposalCandidate(txs.targets, txs.values, txs.signatures, txs.calldatas, description, slug, 0); @@ -203,8 +245,7 @@ contract NounsDAODataTest is Test, SigUtils, NounsDAODataEvents { function test_createProposalCandidate_revertsOnSlugReuseBySameProposer() public { string memory description = 'some description'; string memory slug = 'some slug'; - NounsDAOV3Proposals.ProposalTxs memory txs = createTxs(address(0), 0, 'some signature', 'some data'); - tokenLikeMock.setPriorVotes(address(this), block.number - 1, 1); + NounsDAOProposals.ProposalTxs memory txs = createTxs(address(0), 0, 'some signature', 'some data'); data.createProposalCandidate(txs.targets, txs.values, txs.signatures, txs.calldatas, description, slug, 0); vm.expectRevert(abi.encodeWithSelector(NounsDAOData.SlugAlreadyUsed.selector)); @@ -212,12 +253,9 @@ contract NounsDAODataTest is Test, SigUtils, NounsDAODataEvents { } function test_createProposalCandidate_worksWithSameSlugButDifferentProposers() public { - address otherProposer = makeAddr('other proposer'); string memory description = 'some description'; string memory slug = 'some slug'; - NounsDAOV3Proposals.ProposalTxs memory txs = createTxs(address(0), 0, 'some signature', 'some data'); - tokenLikeMock.setPriorVotes(address(this), block.number - 1, 1); - tokenLikeMock.setPriorVotes(otherProposer, block.number - 1, 1); + NounsDAOProposals.ProposalTxs memory txs = createTxs(address(0), 0, 'some signature', 'some data'); data.createProposalCandidate(txs.targets, txs.values, txs.signatures, txs.calldatas, description, slug, 0); vm.prank(otherProposer); @@ -227,7 +265,7 @@ contract NounsDAODataTest is Test, SigUtils, NounsDAODataEvents { function test_updateProposalCandidate_revertsForNonNounerAndNoPayment() public { string memory description = 'some description'; string memory slug = 'some slug'; - NounsDAOV3Proposals.ProposalTxs memory txs = createTxs(address(0), 0, 'some signature', 'some data'); + NounsDAOProposals.ProposalTxs memory txs = createTxs(address(0), 0, 'some signature', 'some data'); data.createProposalCandidate{ value: data.createCandidateCost() }( txs.targets, txs.values, @@ -239,6 +277,7 @@ contract NounsDAODataTest is Test, SigUtils, NounsDAODataEvents { ); vm.expectRevert(abi.encodeWithSelector(NounsDAOData.MustBeNounerOrPaySufficientFee.selector)); + vm.prank(notNouner); data.updateProposalCandidate( txs.targets, txs.values, @@ -251,8 +290,47 @@ contract NounsDAODataTest is Test, SigUtils, NounsDAODataEvents { ); } + function test_createProposalCandidate_givenMoreThan10Txs_reverts() public { + vm.prank(dataAdmin); + data.setCreateCandidateCost(0); + + string memory description = 'some description'; + string memory slug = 'some slug'; + NounsDAOProposals.ProposalTxs memory txs = createTxs(11, address(0), 0, 'some signature', 'some data'); + + vm.expectRevert(NounsDAOProposals.TooManyActions.selector); + data.createProposalCandidate(txs.targets, txs.values, txs.signatures, txs.calldatas, description, slug, 0); + } + + function test_createProposalCandidate_givenZeroTxs_reverts() public { + vm.prank(dataAdmin); + data.setCreateCandidateCost(0); + + string memory description = 'some description'; + string memory slug = 'some slug'; + NounsDAOProposals.ProposalTxs memory txs = createTxs(0, address(0), 0, 'some signature', 'some data'); + + vm.expectRevert(NounsDAOProposals.MustProvideActions.selector); + data.createProposalCandidate(txs.targets, txs.values, txs.signatures, txs.calldatas, description, slug, 0); + } + + function test_createProposalCandidate_givenArityMismatch_reverts() public { + vm.prank(dataAdmin); + data.setCreateCandidateCost(0); + + string memory description = 'some description'; + string memory slug = 'some slug'; + NounsDAOProposals.ProposalTxs memory txs = createTxs(1, address(0), 0, 'some signature', 'some data'); + uint256[] memory values = new uint256[](2); + + vm.expectRevert(NounsDAOProposals.ProposalInfoArityMismatch.selector); + data.createProposalCandidate(txs.targets, values, txs.signatures, txs.calldatas, description, slug, 0); + } +} + +contract NounsDAOData_UpdateCandidateTest is NounsDAODataBaseTest { function test_updateProposalCandidate_revertsOnUnseenSlug() public { - NounsDAOV3Proposals.ProposalTxs memory txs = createTxs(address(0), 0, 'some signature', 'some data'); + NounsDAOProposals.ProposalTxs memory txs = createTxs(address(0), 0, 'some signature', 'some data'); uint256 value = data.updateCandidateCost(); vm.expectRevert(abi.encodeWithSelector(NounsDAOData.SlugDoesNotExist.selector)); @@ -269,10 +347,9 @@ contract NounsDAODataTest is Test, SigUtils, NounsDAODataEvents { } function test_updateProposalCandidate_worksForNouner() public { - tokenLikeMock.setPriorVotes(address(this), block.number - 1, 1); string memory description = 'some description'; string memory slug = 'some slug'; - NounsDAOV3Proposals.ProposalTxs memory txs = createTxs(address(0), 0, 'some signature', 'some data'); + NounsDAOProposals.ProposalTxs memory txs = createTxs(address(0), 0, 'some signature', 'some data'); data.createProposalCandidate(txs.targets, txs.values, txs.signatures, txs.calldatas, description, slug, 0); string memory updateDescription = 'new description'; @@ -286,7 +363,7 @@ contract NounsDAODataTest is Test, SigUtils, NounsDAODataEvents { updateDescription, slug, 0, - keccak256(NounsDAOV3Proposals.calcProposalEncodeData(address(this), txs, updateDescription)), + keccak256(NounsDAOProposals.calcProposalEncodeData(address(this), txs, updateDescription)), 'reason' ); @@ -305,7 +382,7 @@ contract NounsDAODataTest is Test, SigUtils, NounsDAODataEvents { function test_updateProposalCandidate_worksForNonNounerWithEnoughPayment() public { string memory description = 'some description'; string memory slug = 'some slug'; - NounsDAOV3Proposals.ProposalTxs memory txs = createTxs(address(0), 0, 'some signature', 'some data'); + NounsDAOProposals.ProposalTxs memory txs = createTxs(address(0), 0, 'some signature', 'some data'); data.createProposalCandidate{ value: data.createCandidateCost() }( txs.targets, txs.values, @@ -328,7 +405,7 @@ contract NounsDAODataTest is Test, SigUtils, NounsDAODataEvents { updateDescription, slug, 0, - keccak256(NounsDAOV3Proposals.calcProposalEncodeData(address(this), txs, updateDescription)), + keccak256(NounsDAOProposals.calcProposalEncodeData(address(this), txs, updateDescription)), 'reason' ); @@ -349,7 +426,7 @@ contract NounsDAODataTest is Test, SigUtils, NounsDAODataEvents { function test_updateProposalCandidate_givenFeeRecipientZero_accumelatesETHFee() public { string memory description = 'some description'; string memory slug = 'some slug'; - NounsDAOV3Proposals.ProposalTxs memory txs = createTxs(address(0), 0, 'some signature', 'some data'); + NounsDAOProposals.ProposalTxs memory txs = createTxs(address(0), 0, 'some signature', 'some data'); data.createProposalCandidate{ value: data.createCandidateCost() }( txs.targets, txs.values, @@ -376,7 +453,7 @@ contract NounsDAODataTest is Test, SigUtils, NounsDAODataEvents { updateDescription, slug, 0, - keccak256(NounsDAOV3Proposals.calcProposalEncodeData(address(this), txs, updateDescription)), + keccak256(NounsDAOProposals.calcProposalEncodeData(address(this), txs, updateDescription)), 'reason' ); @@ -399,7 +476,7 @@ contract NounsDAODataTest is Test, SigUtils, NounsDAODataEvents { data.setUpdateCandidateCost(0); string memory description = 'some description'; string memory slug = 'some slug'; - NounsDAOV3Proposals.ProposalTxs memory txs = createTxs(address(0), 0, 'some signature', 'some data'); + NounsDAOProposals.ProposalTxs memory txs = createTxs(address(0), 0, 'some signature', 'some data'); data.createProposalCandidate{ value: data.createCandidateCost() }( txs.targets, txs.values, @@ -421,7 +498,7 @@ contract NounsDAODataTest is Test, SigUtils, NounsDAODataEvents { updateDescription, slug, 0, - keccak256(NounsDAOV3Proposals.calcProposalEncodeData(address(this), txs, updateDescription)), + keccak256(NounsDAOProposals.calcProposalEncodeData(address(this), txs, updateDescription)), 'reason' ); @@ -437,13 +514,81 @@ contract NounsDAODataTest is Test, SigUtils, NounsDAODataEvents { ); } + function test_updateProposalCandidate_givenMoreThan10Txs_reverts() public { + vm.prank(dataAdmin); + data.setUpdateCandidateCost(0); + string memory description = 'some description'; + string memory slug = 'some slug'; + NounsDAOProposals.ProposalTxs memory txs = createTxs(address(0), 0, 'some signature', 'some data'); + data.createProposalCandidate(txs.targets, txs.values, txs.signatures, txs.calldatas, description, slug, 0); + txs = createTxs(11, address(0), 0, 'some signature', 'some data'); + + vm.expectRevert(NounsDAOProposals.TooManyActions.selector); + data.updateProposalCandidate( + txs.targets, + txs.values, + txs.signatures, + txs.calldatas, + description, + slug, + 0, + 'reason' + ); + } + + function test_updateProposalCandidate_givenZeroTxs_reverts() public { + vm.prank(dataAdmin); + data.setUpdateCandidateCost(0); + string memory description = 'some description'; + string memory slug = 'some slug'; + NounsDAOProposals.ProposalTxs memory txs = createTxs(address(0), 0, 'some signature', 'some data'); + data.createProposalCandidate(txs.targets, txs.values, txs.signatures, txs.calldatas, description, slug, 0); + txs = createTxs(0, address(0), 0, 'some signature', 'some data'); + + vm.expectRevert(NounsDAOProposals.MustProvideActions.selector); + data.updateProposalCandidate( + txs.targets, + txs.values, + txs.signatures, + txs.calldatas, + description, + slug, + 0, + 'reason' + ); + } + + function test_updateProposalCandidate_givenArityMismatch_reverts() public { + vm.prank(dataAdmin); + data.setUpdateCandidateCost(0); + string memory description = 'some description'; + string memory slug = 'some slug'; + NounsDAOProposals.ProposalTxs memory txs = createTxs(address(0), 0, 'some signature', 'some data'); + data.createProposalCandidate(txs.targets, txs.values, txs.signatures, txs.calldatas, description, slug, 0); + uint256[] memory values = new uint256[](2); + + vm.expectRevert(NounsDAOProposals.ProposalInfoArityMismatch.selector); + data.updateProposalCandidate( + txs.targets, + values, + txs.signatures, + txs.calldatas, + description, + slug, + 0, + 'reason' + ); + } +} + +contract NounsDAOData_CancelCandidateTest is NounsDAODataBaseTest { function test_cancelProposalCandidate_revertsOnUnseenSlug() public { vm.expectRevert(abi.encodeWithSelector(NounsDAOData.SlugDoesNotExist.selector)); data.cancelProposalCandidate('slug'); } function test_cancelProposalCandidate_emitsACancelEvent() public { - NounsDAOV3Proposals.ProposalTxs memory txs = createTxs(address(0), 0, 'some signature', 'some data'); + NounsDAOProposals.ProposalTxs memory txs = createTxs(address(0), 0, 'some signature', 'some data'); data.createProposalCandidate{ value: data.createCandidateCost() }( txs.targets, txs.values, @@ -459,7 +604,9 @@ contract NounsDAODataTest is Test, SigUtils, NounsDAODataEvents { data.cancelProposalCandidate('slug'); } +} +contract NounsDAOData_AddSignatureTest is NounsDAODataBaseTest { function test_addSignature_revertsOnUnseenSlug() public { address signer = makeAddr('signer'); bytes memory sig = new bytes(0); @@ -472,7 +619,7 @@ contract NounsDAODataTest is Test, SigUtils, NounsDAODataEvents { function test_addSignature_revertsWhenSenderIsntSigner() public { string memory description = 'some description'; string memory slug = 'slug'; - NounsDAOV3Proposals.ProposalTxs memory txs = createTxs(address(0), 0, 'some signature', 'some data'); + NounsDAOProposals.ProposalTxs memory txs = createTxs(address(0), 0, 'some signature', 'some data'); data.createProposalCandidate{ value: data.createCandidateCost() }( txs.targets, txs.values, @@ -497,7 +644,7 @@ contract NounsDAODataTest is Test, SigUtils, NounsDAODataEvents { verifyingContract, 'Nouns DAO' ); - bytes memory encodedProp = NounsDAOV3Proposals.calcProposalEncodeData(address(this), txs, description); + bytes memory encodedProp = NounsDAOProposals.calcProposalEncodeData(address(this), txs, description); vm.expectRevert(abi.encodeWithSelector(NounsDAOData.InvalidSignature.selector)); vm.prank(makeAddr('not signer')); @@ -507,7 +654,7 @@ contract NounsDAODataTest is Test, SigUtils, NounsDAODataEvents { function test_addSignature_emitsEvent() public { string memory description = 'some description'; string memory slug = 'slug'; - NounsDAOV3Proposals.ProposalTxs memory txs = createTxs(address(0), 0, 'some signature', 'some data'); + NounsDAOProposals.ProposalTxs memory txs = createTxs(address(0), 0, 'some signature', 'some data'); data.createProposalCandidate{ value: data.createCandidateCost() }( txs.targets, txs.values, @@ -521,7 +668,7 @@ contract NounsDAODataTest is Test, SigUtils, NounsDAODataEvents { (address signer, uint256 signerKey) = makeAddrAndKey('signer'); address proposer = address(this); uint256 expiration = 1234; - address verifyingContract = nounsDao; + address verifyingContract = address(nounsDao); string memory reason = 'reason'; bytes memory sig = signProposal( proposer, @@ -532,9 +679,9 @@ contract NounsDAODataTest is Test, SigUtils, NounsDAODataEvents { verifyingContract, 'Nouns DAO' ); - bytes memory encodedProp = NounsDAOV3Proposals.calcProposalEncodeData(address(this), txs, description); - bytes32 sigDigest = NounsDAOV3Proposals.sigDigest( - NounsDAOV3Proposals.PROPOSAL_TYPEHASH, + bytes memory encodedProp = NounsDAOProposals.calcProposalEncodeData(address(this), txs, description); + bytes32 sigDigest = NounsDAOProposals.sigDigest( + NounsDAOProposals.PROPOSAL_TYPEHASH, encodedProp, expiration, verifyingContract @@ -546,17 +693,15 @@ contract NounsDAODataTest is Test, SigUtils, NounsDAODataEvents { vm.prank(signer); data.addSignature(sig, expiration, proposer, slug, 0, encodedProp, reason); } +} +contract NounsDAOData_SendFeedbackTest is NounsDAODataBaseTest { function test_sendFeedback_revertsWithBadSupportValue() public { - tokenLikeMock.setPriorVotes(address(this), block.number - 1, 1); - vm.expectRevert(abi.encodeWithSelector(NounsDAOData.InvalidSupportValue.selector)); data.sendFeedback(1, 3, 'some reason'); } function test_sendFeedback_emitsEventForNouner() public { - tokenLikeMock.setPriorVotes(address(this), block.number - 1, 3); - vm.expectEmit(true, true, true, true); emit FeedbackSent(address(this), 1, 1, 'some reason'); @@ -577,7 +722,7 @@ contract NounsDAODataTest is Test, SigUtils, NounsDAODataEvents { function test_sendCandidateFeedback_revertsWithBadSupportValue() public { string memory slug = 'some slug'; - NounsDAOV3Proposals.ProposalTxs memory txs = createTxs(address(0), 0, 'some signature', 'some data'); + NounsDAOProposals.ProposalTxs memory txs = createTxs(address(0), 0, 'some signature', 'some data'); data.createProposalCandidate{ value: data.createCandidateCost() }( txs.targets, txs.values, @@ -596,9 +741,8 @@ contract NounsDAODataTest is Test, SigUtils, NounsDAODataEvents { function test_sendCandidateFeedback_emitsEventForNouner() public { address nouner = makeAddr('nouner'); - tokenLikeMock.setPriorVotes(nouner, block.number - 1, 3); string memory slug = 'some slug'; - NounsDAOV3Proposals.ProposalTxs memory txs = createTxs(address(0), 0, 'some signature', 'some data'); + NounsDAOProposals.ProposalTxs memory txs = createTxs(address(0), 0, 'some signature', 'some data'); data.createProposalCandidate{ value: data.createCandidateCost() }( txs.targets, txs.values, @@ -621,7 +765,7 @@ contract NounsDAODataTest is Test, SigUtils, NounsDAODataEvents { function test_sendCandidateFeedback_emitsEventForNonNouner() public { address nonNouner = makeAddr('non nouner'); string memory slug = 'some slug'; - NounsDAOV3Proposals.ProposalTxs memory txs = createTxs(address(0), 0, 'some signature', 'some data'); + NounsDAOProposals.ProposalTxs memory txs = createTxs(address(0), 0, 'some signature', 'some data'); data.createProposalCandidate{ value: data.createCandidateCost() }( txs.targets, txs.values, @@ -640,7 +784,9 @@ contract NounsDAODataTest is Test, SigUtils, NounsDAODataEvents { vm.prank(nonNouner); data.sendCandidateFeedback(address(this), 'some slug', support, reason); } +} +contract NounsDAOData_AdminFunctionsTest is NounsDAODataBaseTest { function test_setCreateCandidateCost_revertsForNonAdmin() public { vm.expectRevert('Ownable: caller is not the owner'); data.setCreateCandidateCost(0.42 ether); @@ -720,13 +866,122 @@ contract NounsDAODataTest is Test, SigUtils, NounsDAODataEvents { assertEq(recipient.balance, 1.42 ether); } +} - function createTxs( +contract NounsDAOData_CreateCandidateToUpdateProposalTest is NounsDAODataBaseTest { + address signer; + uint256 signerPK; + uint256 proposalId; + NounsDAOProposals.ProposalTxs updateTxs; + string updateDescription = 'some description'; + + function setUp() public override { + super.setUp(); + (signer, signerPK) = makeAddrAndKey('signerWithVote1'); + bidAndSettleAuction(auction, signer); + + proposalId = proposeBySigs( + notNouner, + signer, + signerPK, + createTxs(makeAddr('target'), 0.142 ether, '', ''), + 'description', + block.timestamp + 7 days + ); + + updateTxs = createTxs(makeAddr('target'), 4.2 ether, '', ''); + } + + function test_givenProposalInUpdatableStateAndSenderIsProposerAndSenderNotNounder_worksWithNoFee() public { + bytes32 encodedProp = keccak256( + abi.encodePacked( + proposalId, + NounsDAOProposals.calcProposalEncodeData(notNouner, updateTxs, updateDescription) + ) + ); + + vm.expectEmit(true, true, true, true); + emit ProposalCandidateCreated( + notNouner, + updateTxs.targets, + updateTxs.values, + updateTxs.signatures, + updateTxs.calldatas, + updateDescription, + 'some slug', + proposalId, + encodedProp + ); + + vm.prank(notNouner); + data.createProposalCandidate( + updateTxs.targets, + updateTxs.values, + updateTxs.signatures, + updateTxs.calldatas, + updateDescription, + 'some slug', + proposalId + ); + } + + function test_givenProposalNotUpdatable_reverts() public { + vm.roll(nounsDao.proposalsV3(proposalId).updatePeriodEndBlock + 1); + + vm.expectRevert(NounsDAOData.ProposalToUpdateMustBeUpdatable.selector); + vm.prank(notNouner); + data.createProposalCandidate( + updateTxs.targets, + updateTxs.values, + updateTxs.signatures, + updateTxs.calldatas, + updateDescription, + 'some slug', + proposalId + ); + } + + function test_givenSenderIsntProposer_reverts() public { + vm.expectRevert(NounsDAOData.OnlyProposerCanCreateUpdateCandidate.selector); + vm.prank(makeAddr('not proposer')); + data.createProposalCandidate( + updateTxs.targets, + updateTxs.values, + updateTxs.signatures, + updateTxs.calldatas, + updateDescription, + 'some slug', + proposalId + ); + } + + function test_givenProposalNotBySigs_reverts() public { + address nouner = makeAddr('nouner'); + bidAndSettleAuction(auction, nouner); + proposalId = propose(nouner, makeAddr('target'), 0.142 ether, '', '', 'description'); + + vm.expectRevert(NounsDAOData.UpdateProposalCandidatesOnlyWorkWithProposalsBySigs.selector); + vm.prank(nouner); + data.createProposalCandidate( + updateTxs.targets, + updateTxs.values, + updateTxs.signatures, + updateTxs.calldatas, + updateDescription, + 'some slug', + proposalId + ); + } + + function propose( + address proposer, address target, uint256 value, string memory signature, - bytes memory callData - ) internal pure returns (NounsDAOV3Proposals.ProposalTxs memory) { + bytes memory data, + string memory description + ) internal returns (uint256) { + vm.prank(proposer); address[] memory targets = new address[](1); targets[0] = target; uint256[] memory values = new uint256[](1); @@ -734,8 +989,46 @@ contract NounsDAODataTest is Test, SigUtils, NounsDAODataEvents { string[] memory signatures = new string[](1); signatures[0] = signature; bytes[] memory calldatas = new bytes[](1); - calldatas[0] = callData; + calldatas[0] = data; + return nounsDao.propose(targets, values, signatures, calldatas, description); + } + + function proposeBySigs( + address proposer, + address signer_, + uint256 signerPK_, + NounsDAOProposals.ProposalTxs memory txs, + string memory description, + uint256 expirationTimestamp + ) internal returns (uint256 proposalId_) { + address[] memory signers = new address[](1); + signers[0] = signer_; + uint256[] memory signerPKs = new uint256[](1); + signerPKs[0] = signerPK_; + uint256[] memory expirationTimestamps = new uint256[](1); + expirationTimestamps[0] = expirationTimestamp; + + return proposeBySigs(proposer, signers, signerPKs, expirationTimestamps, txs, description); + } - return NounsDAOV3Proposals.ProposalTxs(targets, values, signatures, calldatas); + function proposeBySigs( + address proposer, + address[] memory signers, + uint256[] memory signerPKs, + uint256[] memory expirationTimestamps, + NounsDAOProposals.ProposalTxs memory txs, + string memory description + ) internal returns (uint256 proposalId_) { + NounsDAOTypes.ProposerSignature[] memory sigs = new NounsDAOTypes.ProposerSignature[](signers.length); + for (uint256 i = 0; i < signers.length; ++i) { + sigs[i] = NounsDAOTypes.ProposerSignature( + signProposal(proposer, signerPKs[i], txs, description, expirationTimestamps[i], address(nounsDao)), + signers[i], + expirationTimestamps[i] + ); + } + + vm.prank(proposer); + proposalId_ = nounsDao.proposeBySigs(sigs, txs.targets, txs.values, txs.signatures, txs.calldatas, description); } } diff --git a/packages/nouns-contracts/test/foundry/NounsDAOLogicV3/CancelProposal.t.sol b/packages/nouns-contracts/test/foundry/NounsDAOLogic/CancelProposal.t.sol similarity index 86% rename from packages/nouns-contracts/test/foundry/NounsDAOLogicV3/CancelProposal.t.sol rename to packages/nouns-contracts/test/foundry/NounsDAOLogic/CancelProposal.t.sol index d3bd5f8a8f..ccbf85d785 100644 --- a/packages/nouns-contracts/test/foundry/NounsDAOLogicV3/CancelProposal.t.sol +++ b/packages/nouns-contracts/test/foundry/NounsDAOLogic/CancelProposal.t.sol @@ -2,11 +2,11 @@ pragma solidity ^0.8.15; import 'forge-std/Test.sol'; -import { NounsDAOLogicV3BaseTest } from './NounsDAOLogicV3BaseTest.sol'; -import { NounsDAOStorageV3 } from '../../../contracts/governance/NounsDAOInterfaces.sol'; -import { NounsDAOV3Proposals } from '../../../contracts/governance/NounsDAOV3Proposals.sol'; +import { NounsDAOLogicBaseTest } from './NounsDAOLogicBaseTest.sol'; +import { NounsDAOTypes } from '../../../contracts/governance/NounsDAOInterfaces.sol'; +import { NounsDAOProposals } from '../../../contracts/governance/NounsDAOProposals.sol'; -abstract contract ZeroState is NounsDAOLogicV3BaseTest { +abstract contract ZeroState is NounsDAOLogicBaseTest { address proposer = makeAddr('proposer'); address rando = makeAddr('rando'); address otherUser = makeAddr('otherUser'); @@ -21,7 +21,7 @@ abstract contract ZeroState is NounsDAOLogicV3BaseTest { emit ProposalCanceled(proposalId); vm.prank(proposer); dao.cancel(proposalId); - assertEq(uint256(dao.state(proposalId)), uint256(NounsDAOStorageV3.ProposalState.Canceled)); + assertEq(uint256(dao.state(proposalId)), uint256(NounsDAOTypes.ProposalState.Canceled)); } function verifyRandoCantCancel() internal { @@ -54,7 +54,7 @@ abstract contract ProposalUpdatableState is ZeroState { proposalId = propose(proposer, target, 0, '', '', ''); vm.roll(block.number + 1); - assertEq(uint256(dao.state(proposalId)), uint256(NounsDAOStorageV3.ProposalState.Updatable)); + assertEq(uint256(dao.state(proposalId)), uint256(NounsDAOTypes.ProposalState.Updatable)); } } @@ -74,14 +74,14 @@ abstract contract IsCancellable is ZeroState { abstract contract IsNotCancellable is ZeroState { function test_proposerCantCancel() public { - vm.expectRevert(NounsDAOV3Proposals.CantCancelProposalAtFinalState.selector); + vm.expectRevert(NounsDAOProposals.CantCancelProposalAtFinalState.selector); vm.prank(proposer); dao.cancel(proposalId); } } contract ProposalUpdatableStateTest is ProposalUpdatableState, IsCancellable { - function setUp() public override(ProposalUpdatableState, NounsDAOLogicV3BaseTest) { + function setUp() public override(ProposalUpdatableState, NounsDAOLogicBaseTest) { ProposalUpdatableState.setUp(); } } @@ -91,12 +91,12 @@ abstract contract ProposalPendingState is ProposalUpdatableState { super.setUp(); vm.roll(dao.proposalsV3(proposalId).updatePeriodEndBlock + 1); - assertEq(uint256(dao.state(proposalId)), uint256(NounsDAOStorageV3.ProposalState.Pending)); + assertEq(uint256(dao.state(proposalId)), uint256(NounsDAOTypes.ProposalState.Pending)); } } contract ProposalPendingStateTest is ProposalPendingState, IsCancellable { - function setUp() public override(ProposalPendingState, NounsDAOLogicV3BaseTest) { + function setUp() public override(ProposalPendingState, NounsDAOLogicBaseTest) { ProposalPendingState.setUp(); } } @@ -106,12 +106,12 @@ abstract contract ProposalActiveState is ProposalPendingState { super.setUp(); vm.roll(dao.proposalsV3(proposalId).startBlock + 1); - assertEq(uint256(dao.state(proposalId)), uint256(NounsDAOStorageV3.ProposalState.Active)); + assertEq(uint256(dao.state(proposalId)), uint256(NounsDAOTypes.ProposalState.Active)); } } contract ProposalActiveStateTest is ProposalActiveState, IsCancellable { - function setUp() public override(ProposalActiveState, NounsDAOLogicV3BaseTest) { + function setUp() public override(ProposalActiveState, NounsDAOLogicBaseTest) { ProposalActiveState.setUp(); } } @@ -125,12 +125,12 @@ abstract contract ProposalObjectionPeriodState is ProposalActiveState { dao.castVote(proposalId, 1); vm.roll(dao.proposalsV3(proposalId).endBlock + 1); - assertEq(uint256(dao.state(proposalId)), uint256(NounsDAOStorageV3.ProposalState.ObjectionPeriod)); + assertEq(uint256(dao.state(proposalId)), uint256(NounsDAOTypes.ProposalState.ObjectionPeriod)); } } contract ProposalObjectionPeriodStateTest is ProposalObjectionPeriodState, IsCancellable { - function setUp() public override(ProposalObjectionPeriodState, NounsDAOLogicV3BaseTest) { + function setUp() public override(ProposalObjectionPeriodState, NounsDAOLogicBaseTest) { ProposalObjectionPeriodState.setUp(); } } @@ -143,12 +143,12 @@ abstract contract ProposalSucceededState is ProposalActiveState { dao.castVote(proposalId, 1); vm.roll(dao.proposalsV3(proposalId).endBlock + 1); - assertEq(uint256(dao.state(proposalId)), uint256(NounsDAOStorageV3.ProposalState.Succeeded)); + assertEq(uint256(dao.state(proposalId)), uint256(NounsDAOTypes.ProposalState.Succeeded)); } } contract ProposalSucceededStateTest is ProposalSucceededState, IsCancellable { - function setUp() public override(ProposalSucceededState, NounsDAOLogicV3BaseTest) { + function setUp() public override(ProposalSucceededState, NounsDAOLogicBaseTest) { ProposalSucceededState.setUp(); } } @@ -158,12 +158,12 @@ abstract contract ProposalQueuedState is ProposalSucceededState { super.setUp(); dao.queue(proposalId); - assertEq(uint256(dao.state(proposalId)), uint256(NounsDAOStorageV3.ProposalState.Queued)); + assertEq(uint256(dao.state(proposalId)), uint256(NounsDAOTypes.ProposalState.Queued)); } } contract ProposalQueuedStateTest is ProposalQueuedState, IsCancellable { - function setUp() public override(ProposalQueuedState, NounsDAOLogicV3BaseTest) { + function setUp() public override(ProposalQueuedState, NounsDAOLogicBaseTest) { ProposalQueuedState.setUp(); } } @@ -174,12 +174,12 @@ abstract contract ProposalExecutedState is ProposalQueuedState { vm.warp(dao.proposalsV3(proposalId).eta + 1); dao.execute(proposalId); - assertEq(uint256(dao.state(proposalId)), uint256(NounsDAOStorageV3.ProposalState.Executed)); + assertEq(uint256(dao.state(proposalId)), uint256(NounsDAOTypes.ProposalState.Executed)); } } contract ProposalExecutedStateTest is ProposalExecutedState, IsNotCancellable { - function setUp() public override(ProposalExecutedState, NounsDAOLogicV3BaseTest) { + function setUp() public override(ProposalExecutedState, NounsDAOLogicBaseTest) { ProposalExecutedState.setUp(); } } @@ -189,12 +189,12 @@ abstract contract ProposalDefeatedState is ProposalActiveState { super.setUp(); vm.roll(dao.proposalsV3(proposalId).endBlock + 1); - assertEq(uint256(dao.state(proposalId)), uint256(NounsDAOStorageV3.ProposalState.Defeated)); + assertEq(uint256(dao.state(proposalId)), uint256(NounsDAOTypes.ProposalState.Defeated)); } } contract ProposalDefeatedStateTest is ProposalDefeatedState, IsNotCancellable { - function setUp() public override(ProposalDefeatedState, NounsDAOLogicV3BaseTest) { + function setUp() public override(ProposalDefeatedState, NounsDAOLogicBaseTest) { ProposalDefeatedState.setUp(); } } diff --git a/packages/nouns-contracts/test/foundry/NounsDAOLogicV3/CancelProposalBySigs.t.sol b/packages/nouns-contracts/test/foundry/NounsDAOLogic/CancelProposalBySigs.t.sol similarity index 83% rename from packages/nouns-contracts/test/foundry/NounsDAOLogicV3/CancelProposalBySigs.t.sol rename to packages/nouns-contracts/test/foundry/NounsDAOLogic/CancelProposalBySigs.t.sol index 6647452dd1..ef5276b6f7 100644 --- a/packages/nouns-contracts/test/foundry/NounsDAOLogicV3/CancelProposalBySigs.t.sol +++ b/packages/nouns-contracts/test/foundry/NounsDAOLogic/CancelProposalBySigs.t.sol @@ -2,11 +2,11 @@ pragma solidity ^0.8.15; import 'forge-std/Test.sol'; -import { NounsDAOLogicV3BaseTest } from './NounsDAOLogicV3BaseTest.sol'; -import { NounsDAOStorageV3 } from '../../../contracts/governance/NounsDAOInterfaces.sol'; -import { NounsDAOV3Proposals } from '../../../contracts/governance/NounsDAOV3Proposals.sol'; +import { NounsDAOLogicBaseTest } from './NounsDAOLogicBaseTest.sol'; +import { NounsDAOTypes } from '../../../contracts/governance/NounsDAOInterfaces.sol'; +import { NounsDAOProposals } from '../../../contracts/governance/NounsDAOProposals.sol'; -abstract contract ZeroState is NounsDAOLogicV3BaseTest { +abstract contract ZeroState is NounsDAOLogicBaseTest { address proposer = makeAddr('proposer'); address rando = makeAddr('rando'); address otherUser = makeAddr('otherUser'); @@ -30,10 +30,10 @@ abstract contract ProposalUpdatableState is ZeroState { vm.roll(block.number + 1); vm.stopPrank(); - NounsDAOV3Proposals.ProposalTxs memory txs = makeTxs(makeAddr('target'), 0, '', ''); + NounsDAOProposals.ProposalTxs memory txs = makeTxs(makeAddr('target'), 0, '', ''); uint256 expirationTimestamp = block.timestamp + 1234; - NounsDAOStorageV3.ProposerSignature[] memory proposerSignatures = new NounsDAOStorageV3.ProposerSignature[](1); - proposerSignatures[0] = NounsDAOStorageV3.ProposerSignature( + NounsDAOTypes.ProposerSignature[] memory proposerSignatures = new NounsDAOTypes.ProposerSignature[](1); + proposerSignatures[0] = NounsDAOTypes.ProposerSignature( signProposal(proposer, signerWithVotePK, txs, 'description', expirationTimestamp, address(dao)), signerWithVote, expirationTimestamp @@ -51,7 +51,7 @@ abstract contract ProposalUpdatableState is ZeroState { vm.roll(block.number + 1); - assertEq(uint256(dao.state(proposalId)), uint256(NounsDAOStorageV3.ProposalState.Updatable)); + assertEq(uint256(dao.state(proposalId)), uint256(NounsDAOTypes.ProposalState.Updatable)); } } @@ -61,7 +61,7 @@ abstract contract IsCancellable is ZeroState { emit ProposalCanceled(proposalId); vm.prank(proposer); dao.cancel(proposalId); - assertEq(uint256(dao.state(proposalId)), uint256(NounsDAOStorageV3.ProposalState.Canceled)); + assertEq(uint256(dao.state(proposalId)), uint256(NounsDAOTypes.ProposalState.Canceled)); } function test_randoCantCancel() public { @@ -82,14 +82,14 @@ abstract contract IsCancellable is ZeroState { abstract contract IsNotCancellable is ZeroState { function test_proposerCantCancel() public { - vm.expectRevert(NounsDAOV3Proposals.CantCancelProposalAtFinalState.selector); + vm.expectRevert(NounsDAOProposals.CantCancelProposalAtFinalState.selector); vm.prank(proposer); dao.cancel(proposalId); } } contract ProposalUpdatableStateTest is ProposalUpdatableState, IsCancellable { - function setUp() public override(ProposalUpdatableState, NounsDAOLogicV3BaseTest) { + function setUp() public override(ProposalUpdatableState, NounsDAOLogicBaseTest) { ProposalUpdatableState.setUp(); } } @@ -99,12 +99,12 @@ abstract contract ProposalPendingState is ProposalUpdatableState { super.setUp(); vm.roll(dao.proposalsV3(proposalId).updatePeriodEndBlock + 1); - assertEq(uint256(dao.state(proposalId)), uint256(NounsDAOStorageV3.ProposalState.Pending)); + assertEq(uint256(dao.state(proposalId)), uint256(NounsDAOTypes.ProposalState.Pending)); } } contract ProposalPendingStateTest is ProposalPendingState, IsCancellable { - function setUp() public override(ProposalPendingState, NounsDAOLogicV3BaseTest) { + function setUp() public override(ProposalPendingState, NounsDAOLogicBaseTest) { ProposalPendingState.setUp(); } } @@ -114,12 +114,12 @@ abstract contract ProposalActiveState is ProposalPendingState { super.setUp(); vm.roll(dao.proposalsV3(proposalId).startBlock + 1); - assertEq(uint256(dao.state(proposalId)), uint256(NounsDAOStorageV3.ProposalState.Active)); + assertEq(uint256(dao.state(proposalId)), uint256(NounsDAOTypes.ProposalState.Active)); } } contract ProposalActiveStateTest is ProposalActiveState, IsCancellable { - function setUp() public override(ProposalActiveState, NounsDAOLogicV3BaseTest) { + function setUp() public override(ProposalActiveState, NounsDAOLogicBaseTest) { ProposalActiveState.setUp(); } } @@ -133,12 +133,12 @@ abstract contract ProposalObjectionPeriodState is ProposalActiveState { dao.castVote(proposalId, 1); vm.roll(dao.proposalsV3(proposalId).endBlock + 1); - assertEq(uint256(dao.state(proposalId)), uint256(NounsDAOStorageV3.ProposalState.ObjectionPeriod)); + assertEq(uint256(dao.state(proposalId)), uint256(NounsDAOTypes.ProposalState.ObjectionPeriod)); } } contract ProposalObjectionPeriodStateTest is ProposalObjectionPeriodState, IsCancellable { - function setUp() public override(ProposalObjectionPeriodState, NounsDAOLogicV3BaseTest) { + function setUp() public override(ProposalObjectionPeriodState, NounsDAOLogicBaseTest) { ProposalObjectionPeriodState.setUp(); } } @@ -151,12 +151,12 @@ abstract contract ProposalSucceededState is ProposalActiveState { dao.castVote(proposalId, 1); vm.roll(dao.proposalsV3(proposalId).endBlock + 1); - assertEq(uint256(dao.state(proposalId)), uint256(NounsDAOStorageV3.ProposalState.Succeeded)); + assertEq(uint256(dao.state(proposalId)), uint256(NounsDAOTypes.ProposalState.Succeeded)); } } contract ProposalSucceededStateTest is ProposalSucceededState, IsCancellable { - function setUp() public override(ProposalSucceededState, NounsDAOLogicV3BaseTest) { + function setUp() public override(ProposalSucceededState, NounsDAOLogicBaseTest) { ProposalSucceededState.setUp(); } } @@ -166,12 +166,12 @@ abstract contract ProposalQueuedState is ProposalSucceededState { super.setUp(); dao.queue(proposalId); - assertEq(uint256(dao.state(proposalId)), uint256(NounsDAOStorageV3.ProposalState.Queued)); + assertEq(uint256(dao.state(proposalId)), uint256(NounsDAOTypes.ProposalState.Queued)); } } contract ProposalQueuedStateTest is ProposalQueuedState, IsCancellable { - function setUp() public override(ProposalQueuedState, NounsDAOLogicV3BaseTest) { + function setUp() public override(ProposalQueuedState, NounsDAOLogicBaseTest) { ProposalQueuedState.setUp(); } } @@ -182,12 +182,12 @@ abstract contract ProposalExecutedState is ProposalQueuedState { vm.warp(dao.proposalsV3(proposalId).eta + 1); dao.execute(proposalId); - assertEq(uint256(dao.state(proposalId)), uint256(NounsDAOStorageV3.ProposalState.Executed)); + assertEq(uint256(dao.state(proposalId)), uint256(NounsDAOTypes.ProposalState.Executed)); } } contract ProposalExecutedStateTest is ProposalExecutedState, IsNotCancellable { - function setUp() public override(ProposalExecutedState, NounsDAOLogicV3BaseTest) { + function setUp() public override(ProposalExecutedState, NounsDAOLogicBaseTest) { ProposalExecutedState.setUp(); } } @@ -197,12 +197,12 @@ abstract contract ProposalDefeatedState is ProposalActiveState { super.setUp(); vm.roll(dao.proposalsV3(proposalId).endBlock + 1); - assertEq(uint256(dao.state(proposalId)), uint256(NounsDAOStorageV3.ProposalState.Defeated)); + assertEq(uint256(dao.state(proposalId)), uint256(NounsDAOTypes.ProposalState.Defeated)); } } contract ProposalDefeatedStateTest is ProposalDefeatedState, IsNotCancellable { - function setUp() public override(ProposalDefeatedState, NounsDAOLogicV3BaseTest) { + function setUp() public override(ProposalDefeatedState, NounsDAOLogicBaseTest) { ProposalDefeatedState.setUp(); } } diff --git a/packages/nouns-contracts/test/foundry/NounsDAOLogicV3/ForkBlocksProposalExecution.t.sol b/packages/nouns-contracts/test/foundry/NounsDAOLogic/ForkBlocksProposalExecution.t.sol similarity index 84% rename from packages/nouns-contracts/test/foundry/NounsDAOLogicV3/ForkBlocksProposalExecution.t.sol rename to packages/nouns-contracts/test/foundry/NounsDAOLogic/ForkBlocksProposalExecution.t.sol index fd55572337..2ef0f2e4aa 100644 --- a/packages/nouns-contracts/test/foundry/NounsDAOLogicV3/ForkBlocksProposalExecution.t.sol +++ b/packages/nouns-contracts/test/foundry/NounsDAOLogic/ForkBlocksProposalExecution.t.sol @@ -2,10 +2,10 @@ pragma solidity ^0.8.15; import 'forge-std/Test.sol'; -import { NounsDAOLogicV3BaseTest } from './NounsDAOLogicV3BaseTest.sol'; -import { NounsDAOV3Proposals } from '../../../contracts/governance/NounsDAOV3Proposals.sol'; +import { NounsDAOLogicBaseTest } from './NounsDAOLogicBaseTest.sol'; +import { NounsDAOProposals } from '../../../contracts/governance/NounsDAOProposals.sol'; -abstract contract ExecutableProposalState is NounsDAOLogicV3BaseTest { +abstract contract ExecutableProposalState is NounsDAOLogicBaseTest { address user = makeAddr('user'); uint256 proposalId; @@ -57,7 +57,7 @@ abstract contract ExecutableProposalWithActiveForkState is ExecutableProposalSta contract ExecutableProposalWithActiveForkStateTest is ExecutableProposalWithActiveForkState { function test_executionRevertsDuringFork() public { - vm.expectRevert(NounsDAOV3Proposals.CannotExecuteDuringForkingPeriod.selector); + vm.expectRevert(NounsDAOProposals.CannotExecuteDuringForkingPeriod.selector); dao.execute(proposalId); } diff --git a/packages/nouns-contracts/test/foundry/NounsDAOLogic/NounsDAOAdmin.t.sol b/packages/nouns-contracts/test/foundry/NounsDAOLogic/NounsDAOAdmin.t.sol new file mode 100644 index 0000000000..6c002e6349 --- /dev/null +++ b/packages/nouns-contracts/test/foundry/NounsDAOLogic/NounsDAOAdmin.t.sol @@ -0,0 +1,476 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity ^0.8.15; + +import 'forge-std/Test.sol'; +import { NounsDAOLogicBaseTest } from './NounsDAOLogicBaseTest.sol'; +import { NounsDAOAdmin } from '../../../contracts/governance/NounsDAOAdmin.sol'; +import { NounsDAOProxyV3 } from '../../../contracts/governance/NounsDAOProxyV3.sol'; +import { INounsDAOLogic } from '../../../contracts/interfaces/INounsDAOLogic.sol'; +import { NounsDAOTypes } from '../../../contracts/governance/NounsDAOInterfaces.sol'; + +contract NounsDAOLogicAdminTest is NounsDAOLogicBaseTest { + event ForkPeriodSet(uint256 oldForkPeriod, uint256 newForkPeriod); + event ForkThresholdSet(uint256 oldForkThreshold, uint256 newForkThreshold); + event ERC20TokensToIncludeInForkSet(address[] oldErc20Tokens, address[] newErc20tokens); + event ObjectionPeriodDurationSet( + uint32 oldObjectionPeriodDurationInBlocks, + uint32 newObjectionPeriodDurationInBlocks + ); + event ProposalUpdatablePeriodSet( + uint32 oldProposalUpdatablePeriodInBlocks, + uint32 newProposalUpdatablePeriodInBlocks + ); + + address[] tokens; + + function test__setVotingDelay_onlyAdmin() public { + vm.expectRevert(NounsDAOAdmin.AdminOnly.selector); + dao._setVotingDelay(1); + } + + function test__setVotingDelay_worksAndEmits() public { + uint256 expectedValue = dao.votingDelay() + 1; + + vm.expectEmit(true, true, true, true); + emit NounsDAOAdmin.VotingDelaySet(dao.votingDelay(), expectedValue); + + vm.prank(address(dao.timelock())); + dao._setVotingDelay(expectedValue); + + assertEq(dao.votingDelay(), expectedValue); + } + + function test__setVotingPeriod_onlyAdmin() public { + vm.expectRevert(NounsDAOAdmin.AdminOnly.selector); + dao._setVotingPeriod(1); + } + + function test__setVotingPeriod_worksAndEmits() public { + uint256 expectedValue = dao.votingPeriod() + 1; + + vm.expectEmit(true, true, true, true); + emit NounsDAOAdmin.VotingPeriodSet(dao.votingPeriod(), expectedValue); + + vm.prank(address(dao.timelock())); + dao._setVotingPeriod(expectedValue); + + assertEq(dao.votingPeriod(), expectedValue); + } + + function test__setProposalThresholdBPS_onlyAdmin() public { + vm.expectRevert(NounsDAOAdmin.AdminOnly.selector); + dao._setProposalThresholdBPS(1); + } + + function test__setProposalThresholdBPS_worksAndEmits() public { + uint256 expectedValue = dao.proposalThresholdBPS() + 1; + + vm.expectEmit(true, true, true, true); + emit NounsDAOAdmin.ProposalThresholdBPSSet(dao.proposalThresholdBPS(), expectedValue); + + vm.prank(address(dao.timelock())); + dao._setProposalThresholdBPS(expectedValue); + + assertEq(dao.proposalThresholdBPS(), expectedValue); + } + + function test__setObjectionPeriodDurationInBlocks_onlyAdmin() public { + vm.expectRevert(NounsDAOAdmin.AdminOnly.selector); + dao._setObjectionPeriodDurationInBlocks(1); + } + + function test__setObjectionPeriodDurationInBlocks_worksAndEmits() public { + uint32 expectedValue = uint32(dao.objectionPeriodDurationInBlocks()) + 1; + + vm.expectEmit(true, true, true, true); + emit ObjectionPeriodDurationSet(uint32(dao.objectionPeriodDurationInBlocks()), expectedValue); + + vm.prank(address(dao.timelock())); + INounsDAOLogic(address(dao))._setObjectionPeriodDurationInBlocks(expectedValue); + + assertEq(uint32(dao.objectionPeriodDurationInBlocks()), expectedValue); + } + + function test__setProposalUpdatablePeriodInBlocks_onlyAdmin() public { + vm.expectRevert(NounsDAOAdmin.AdminOnly.selector); + dao._setProposalUpdatablePeriodInBlocks(1); + } + + function test__setProposalUpdatablePeriodInBlocks_worksAndEmits() public { + uint32 expectedValue = uint32(dao.proposalUpdatablePeriodInBlocks()) + 1; + + vm.expectEmit(true, true, true, true); + emit ProposalUpdatablePeriodSet(uint32(dao.proposalUpdatablePeriodInBlocks()), expectedValue); + + vm.prank(address(dao.timelock())); + INounsDAOLogic(address(dao))._setProposalUpdatablePeriodInBlocks(expectedValue); + + assertEq(uint32(dao.proposalUpdatablePeriodInBlocks()), expectedValue); + } + + function test__setLastMinuteWindowInBlocks_onlyAdmin() public { + vm.expectRevert(NounsDAOAdmin.AdminOnly.selector); + dao._setLastMinuteWindowInBlocks(1); + } + + function test__setLastMinuteWindowInBlocks_worksAndEmits() public { + uint32 expectedValue = uint32(dao.lastMinuteWindowInBlocks()) + 1; + + vm.expectEmit(true, true, true, true); + emit NounsDAOAdmin.LastMinuteWindowSet(uint32(dao.lastMinuteWindowInBlocks()), expectedValue); + + vm.prank(address(dao.timelock())); + INounsDAOLogic(address(dao))._setLastMinuteWindowInBlocks(expectedValue); + + assertEq(uint32(dao.lastMinuteWindowInBlocks()), expectedValue); + } + + function test__setPendingAdmin_onlyAdmin() public { + vm.expectRevert(NounsDAOAdmin.AdminOnly.selector); + dao._setPendingAdmin(address(1)); + } + + function test__acceptAdmin_givenZeroPendingAdmin_reverts() public { + vm.expectRevert('NounsDAO::_acceptAdmin: pending admin only'); + dao._acceptAdmin(); + } + + function test__acceptAdmin_givenSenderNotPendingAdmin_reverts() public { + vm.prank(address(dao.admin())); + dao._setPendingAdmin(makeAddr('new pending admin')); + + vm.expectRevert('NounsDAO::_acceptAdmin: pending admin only'); + dao._acceptAdmin(); + } + + function test_changingAdmin_worksForAdmin() public { + address newAdmin = makeAddr('new admin'); + address oldAdmin = address(dao.admin()); + assertNotEq(newAdmin, address(dao.admin())); + + vm.expectEmit(true, true, true, true); + emit NounsDAOAdmin.NewPendingAdmin(address(0), newAdmin); + + vm.prank(address(dao.admin())); + dao._setPendingAdmin(newAdmin); + + vm.expectEmit(true, true, true, true); + emit NounsDAOAdmin.NewAdmin(oldAdmin, newAdmin); + vm.expectEmit(true, true, true, true); + emit NounsDAOAdmin.NewPendingAdmin(newAdmin, address(0)); + + vm.prank(newAdmin); + dao._acceptAdmin(); + + assertEq(address(dao.admin()), newAdmin); + } + + function test__setMinQuorumVotesBPS_onlyAdmin() public { + vm.expectRevert(NounsDAOAdmin.AdminOnly.selector); + dao._setMinQuorumVotesBPS(1); + } + + function test__setMinQuorumVotesBPS_worksAndEmits() public { + NounsDAOTypes.DynamicQuorumParams memory oldParams = dao.getDynamicQuorumParamsAt(block.number); + uint16 expectedValue = oldParams.minQuorumVotesBPS + 1; + + vm.expectEmit(true, true, true, true); + emit NounsDAOAdmin.MinQuorumVotesBPSSet(oldParams.minQuorumVotesBPS, expectedValue); + + vm.prank(address(dao.timelock())); + dao._setMinQuorumVotesBPS(expectedValue); + + NounsDAOTypes.DynamicQuorumParams memory newParams = dao.getDynamicQuorumParamsAt(block.number); + assertEq(newParams.minQuorumVotesBPS, expectedValue); + } + + function test__setMaxQuorumVotesBPS_onlyAdmin() public { + vm.expectRevert(NounsDAOAdmin.AdminOnly.selector); + dao._setMaxQuorumVotesBPS(1); + } + + function test__setMaxQuorumVotesBPS_worksAndEmits() public { + NounsDAOTypes.DynamicQuorumParams memory oldParams = dao.getDynamicQuorumParamsAt(block.number); + uint16 expectedValue = oldParams.maxQuorumVotesBPS + 1; + + vm.expectEmit(true, true, true, true); + emit NounsDAOAdmin.MaxQuorumVotesBPSSet(oldParams.maxQuorumVotesBPS, expectedValue); + + vm.prank(address(dao.timelock())); + dao._setMaxQuorumVotesBPS(expectedValue); + + NounsDAOTypes.DynamicQuorumParams memory newParams = dao.getDynamicQuorumParamsAt(block.number); + assertEq(newParams.maxQuorumVotesBPS, expectedValue); + } + + function test__setQuorumCoefficient_onlyAdmin() public { + vm.expectRevert(NounsDAOAdmin.AdminOnly.selector); + dao._setQuorumCoefficient(1); + } + + function test__setQuorumCoefficient_worksAndEmits() public { + NounsDAOTypes.DynamicQuorumParams memory oldParams = dao.getDynamicQuorumParamsAt(block.number); + uint32 expectedValue = oldParams.quorumCoefficient + 1; + + vm.expectEmit(true, true, true, true); + emit NounsDAOAdmin.QuorumCoefficientSet(oldParams.quorumCoefficient, expectedValue); + + vm.prank(address(dao.timelock())); + dao._setQuorumCoefficient(expectedValue); + + NounsDAOTypes.DynamicQuorumParams memory newParams = dao.getDynamicQuorumParamsAt(block.number); + assertEq(newParams.quorumCoefficient, expectedValue); + } + + function test__setDynamicQuorumParams_onlyAdmin() public { + vm.expectRevert(NounsDAOAdmin.AdminOnly.selector); + dao._setDynamicQuorumParams(1, 1, 1); + } + + function test__setDynamicQuorumParams_worksAndEmits() public { + NounsDAOTypes.DynamicQuorumParams memory oldParams = dao.getDynamicQuorumParamsAt(block.number); + NounsDAOTypes.DynamicQuorumParams memory expectedValue = NounsDAOTypes.DynamicQuorumParams({ + minQuorumVotesBPS: oldParams.minQuorumVotesBPS + 1, + maxQuorumVotesBPS: oldParams.maxQuorumVotesBPS + 1, + quorumCoefficient: oldParams.quorumCoefficient + 1 + }); + + vm.expectEmit(true, true, true, true); + emit NounsDAOAdmin.MinQuorumVotesBPSSet(oldParams.minQuorumVotesBPS, expectedValue.minQuorumVotesBPS); + vm.expectEmit(true, true, true, true); + emit NounsDAOAdmin.MaxQuorumVotesBPSSet(oldParams.maxQuorumVotesBPS, expectedValue.maxQuorumVotesBPS); + vm.expectEmit(true, true, true, true); + emit NounsDAOAdmin.QuorumCoefficientSet(oldParams.quorumCoefficient, expectedValue.quorumCoefficient); + + vm.prank(address(dao.timelock())); + dao._setDynamicQuorumParams( + expectedValue.minQuorumVotesBPS, + expectedValue.maxQuorumVotesBPS, + expectedValue.quorumCoefficient + ); + + NounsDAOTypes.DynamicQuorumParams memory newParams = dao.getDynamicQuorumParamsAt(block.number); + assertEq(newParams.minQuorumVotesBPS, expectedValue.minQuorumVotesBPS); + assertEq(newParams.maxQuorumVotesBPS, expectedValue.maxQuorumVotesBPS); + assertEq(newParams.quorumCoefficient, expectedValue.quorumCoefficient); + } + + function test__setForkDAODeployer_onlyAdmin() public { + vm.expectRevert(NounsDAOAdmin.AdminOnly.selector); + dao._setForkDAODeployer(address(1)); + } + + function test__setForkDAODeployer_worksAndEmits() public { + address expectedValue = makeAddr('new fork dao deployer'); + address oldValue = address(dao.forkDAODeployer()); + + vm.expectEmit(true, true, true, true); + emit NounsDAOAdmin.ForkDAODeployerSet(oldValue, expectedValue); + + vm.prank(address(dao.timelock())); + dao._setForkDAODeployer(expectedValue); + + assertEq(address(dao.forkDAODeployer()), expectedValue); + } + + function test_setForkPeriod_onlyAdmin() public { + vm.expectRevert(NounsDAOAdmin.AdminOnly.selector); + dao._setForkPeriod(8 days); + } + + function test_setForkPeriod_works() public { + vm.prank(address(dao.timelock())); + vm.expectEmit(true, true, true, true); + emit ForkPeriodSet(7 days, 8 days); + dao._setForkPeriod(8 days); + + assertEq(dao.forkPeriod(), 8 days); + } + + function test_setForkPeriod_limitedByUpperBound() public { + vm.startPrank(address(dao.timelock())); + + // doesn't revert + dao._setForkPeriod(14 days); + + vm.expectRevert(NounsDAOAdmin.ForkPeriodTooLong.selector); + dao._setForkPeriod(14 days + 1); + } + + function test_setForkPeriod_limitedByLowerBound() public { + vm.startPrank(address(dao.timelock())); + + // doesn't revert + dao._setForkPeriod(2 days); + + vm.expectRevert(NounsDAOAdmin.ForkPeriodTooShort.selector); + dao._setForkPeriod(2 days - 1); + } + + function test_setForkThresholdBPS_onlyAdmin() public { + vm.expectRevert(NounsDAOAdmin.AdminOnly.selector); + dao._setForkThresholdBPS(2000); + } + + function test_setForkThresholdBPS_works() public { + vm.prank(address(dao.timelock())); + vm.expectEmit(true, true, true, true); + emit ForkThresholdSet(2000, 1234); + dao._setForkThresholdBPS(1234); + + assertEq(dao.forkThresholdBPS(), 1234); + } + + function test__setForkParams_onlyAdmin() public { + address[] memory erc20s = new address[](0); + vm.expectRevert(NounsDAOAdmin.AdminOnly.selector); + dao._setForkParams(makeAddr('fork escrow'), makeAddr('fork DAO deployer'), erc20s, 1, 1); + } + + function test__setForkParams_works() public { + address[] memory erc20s = new address[](1); + erc20s[0] = makeAddr('erc20'); + + vm.startPrank(address(dao.timelock())); + dao._setForkParams( + makeAddr('fork escrow'), + makeAddr('fork DAO deployer'), + erc20s, + NounsDAOAdmin.MIN_FORK_PERIOD + 1, + 42 + ); + vm.stopPrank(); + + assertEq(address(dao.forkEscrow()), makeAddr('fork escrow')); + assertEq(address(dao.forkDAODeployer()), makeAddr('fork DAO deployer')); + assertEq(dao.erc20TokensToIncludeInFork().length, 1); + assertEq(dao.erc20TokensToIncludeInFork()[0], erc20s[0]); + assertEq(dao.forkPeriod(), NounsDAOAdmin.MIN_FORK_PERIOD + 1); + assertEq(dao.forkThresholdBPS(), 42); + } + + function test__zeroOutVoteSnapshotBlockSwitchProposalId_onlyAdmin() public { + vm.expectRevert(NounsDAOAdmin.AdminOnly.selector); + dao._zeroOutVoteSnapshotBlockSwitchProposalId(); + } + + function test__zeroOutVoteSnapshotBlockSwitchProposalId_works() public { + vm.prank(address(dao.timelock())); + dao._zeroOutVoteSnapshotBlockSwitchProposalId(); + + assertEq(dao.voteSnapshotBlockSwitchProposalId(), 0); + } + + function test_setErc20TokensToIncludeInFork_onlyAdmin() public { + tokens = [address(1), address(2)]; + + vm.expectRevert(NounsDAOAdmin.AdminOnly.selector); + dao._setErc20TokensToIncludeInFork(tokens); + } + + function test_setErc20TokensToIncludeInFork_works() public { + tokens = [address(1), address(2)]; + + vm.prank(address(dao.timelock())); + vm.expectEmit(true, true, true, true); + emit ERC20TokensToIncludeInForkSet(new address[](0), tokens); + dao._setErc20TokensToIncludeInFork(tokens); + + assertEq(dao.erc20TokensToIncludeInFork(), tokens); + } + + function test_setErc20TokensToIncludeInFork_allowsEmptyArray() public { + tokens = new address[](0); + + vm.prank(address(dao.timelock())); + vm.expectEmit(true, true, true, true); + emit ERC20TokensToIncludeInForkSet(new address[](0), tokens); + dao._setErc20TokensToIncludeInFork(tokens); + + assertEq(dao.erc20TokensToIncludeInFork(), tokens); + } + + function test_setErc20TokensToIncludeInFork_givenDuplicateAddressesInInput_reverts() public { + address[] memory tokens_ = new address[](2); + tokens_[0] = address(42); + tokens_[1] = address(42); + + vm.prank(address(dao.timelock())); + vm.expectRevert(NounsDAOAdmin.DuplicateTokenAddress.selector); + dao._setErc20TokensToIncludeInFork(tokens_); + } + + function test_setForkEscrow_onlyAdmin() public { + vm.expectRevert(NounsDAOAdmin.AdminOnly.selector); + dao._setForkEscrow(address(1)); + } + + function test_setForkEscrow_works() public { + vm.prank(address(dao.timelock())); + dao._setForkEscrow(address(1)); + + assertEq(address(dao.forkEscrow()), address(1)); + } + + function test_setTimelocks_onlyAdmin() public { + vm.expectRevert(NounsDAOAdmin.AdminOnly.selector); + dao._setTimelocksAndAdmin(address(1), address(2), address(3)); + } + + function test_setTimelocks_works() public { + vm.prank(address(dao.timelock())); + dao._setTimelocksAndAdmin(address(1), address(2), address(3)); + + assertEq(address(dao.timelock()), address(1)); + assertEq(address(dao.timelockV1()), address(2)); + assertEq(NounsDAOProxyV3(payable(address(dao))).admin(), address(3)); + } + + function test_setObjectionPeriodDurationInBlocks_onlyAdmin() public { + vm.expectRevert(NounsDAOAdmin.AdminOnly.selector); + INounsDAOLogic(address(dao))._setObjectionPeriodDurationInBlocks(3 days / 12); + } + + function test_setObjectionPeriodDurationInBlocks_worksForAdmin() public { + uint32 blocks = 3 days / 12; + vm.expectEmit(true, true, true, true); + emit ObjectionPeriodDurationSet(10, blocks); + + vm.prank(address(dao.timelock())); + INounsDAOLogic(address(dao))._setObjectionPeriodDurationInBlocks(blocks); + + assertEq(dao.objectionPeriodDurationInBlocks(), blocks); + } + + function test_setObjectionPeriodDurationInBlocks_givenValueAboveUpperBound_reverts() public { + uint32 blocks = 8 days / 12; + + vm.prank(address(dao.timelock())); + vm.expectRevert(NounsDAOAdmin.InvalidObjectionPeriodDurationInBlocks.selector); + INounsDAOLogic(address(dao))._setObjectionPeriodDurationInBlocks(blocks); + } + + function test_setProposalUpdatablePeriodInBlocks_onlyAdmin() public { + vm.expectRevert(NounsDAOAdmin.AdminOnly.selector); + dao._setProposalUpdatablePeriodInBlocks(3 days / 12); + } + + function test_setProposalUpdatablePeriodInBlocks_worksForAdmin() public { + uint32 blocks = 3 days / 12; + vm.expectEmit(true, true, true, true); + emit ProposalUpdatablePeriodSet(10, blocks); + + vm.prank(address(dao.timelock())); + dao._setProposalUpdatablePeriodInBlocks(blocks); + + assertEq(dao.proposalUpdatablePeriodInBlocks(), blocks); + } + + function test_setProposalUpdatablePeriodInBlocks_givenValueAboveUpperBound_reverts() public { + uint32 blocks = 8 days / 12; + + vm.prank(address(dao.timelock())); + vm.expectRevert(NounsDAOAdmin.InvalidProposalUpdatablePeriodInBlocks.selector); + dao._setProposalUpdatablePeriodInBlocks(blocks); + } +} diff --git a/packages/nouns-contracts/test/foundry/NounsDAOLogicV3/NounsDAOV3Fork.t.sol b/packages/nouns-contracts/test/foundry/NounsDAOLogic/NounsDAOFork.t.sol similarity index 89% rename from packages/nouns-contracts/test/foundry/NounsDAOLogicV3/NounsDAOV3Fork.t.sol rename to packages/nouns-contracts/test/foundry/NounsDAOLogic/NounsDAOFork.t.sol index 8520e1dce7..a38bda751c 100644 --- a/packages/nouns-contracts/test/foundry/NounsDAOLogicV3/NounsDAOV3Fork.t.sol +++ b/packages/nouns-contracts/test/foundry/NounsDAOLogic/NounsDAOFork.t.sol @@ -2,15 +2,15 @@ pragma solidity ^0.8.15; import 'forge-std/Test.sol'; -import { NounsDAOLogicV3BaseTest } from './NounsDAOLogicV3BaseTest.sol'; +import { NounsDAOLogicBaseTest } from './NounsDAOLogicBaseTest.sol'; import { ForkDAODeployerMock } from '../helpers/ForkDAODeployerMock.sol'; import { ERC20Mock } from '../helpers/ERC20Mock.sol'; -import { NounsDAOV3Fork } from '../../../contracts/governance/fork/NounsDAOV3Fork.sol'; +import { NounsDAOFork } from '../../../contracts/governance/fork/NounsDAOFork.sol'; import { NounsDAOForkEscrow } from '../../../contracts/governance/fork/NounsDAOForkEscrow.sol'; import { IERC721 } from '@openzeppelin/contracts/token/ERC721/IERC721.sol'; import { INounsDAOForkEscrow } from '../../../contracts/governance/NounsDAOInterfaces.sol'; -abstract contract DAOForkZeroState is NounsDAOLogicV3BaseTest { +abstract contract DAOForkZeroState is NounsDAOLogicBaseTest { address tokenHolder = makeAddr('tokenHolder'); address tokenHolder2 = makeAddr('tokenHolder2'); uint256[] tokenIds; @@ -45,11 +45,7 @@ abstract contract DAOForkZeroState is NounsDAOLogicV3BaseTest { escrow = dao.forkEscrow(); } - function assertOwnerOfTokens( - address token, - uint256[] memory tokenIds_, - address owner - ) internal { + function assertOwnerOfTokens(address token, uint256[] memory tokenIds_, address owner) internal { for (uint256 i = 0; i < tokenIds_.length; i++) { assertEq(IERC721(token).ownerOf(tokenIds_[i]), owner); } @@ -76,27 +72,27 @@ contract DAOForkZeroStateTest is DAOForkZeroState { nounsToken.setApprovalForAll(address(dao), true); vm.expectEmit(true, true, true, true); - emit NounsDAOV3Fork.EscrowedToFork(escrow.forkId(), tokenHolder, tokenIds, proposalIds, 'time to fork'); + emit NounsDAOFork.EscrowedToFork(escrow.forkId(), tokenHolder, tokenIds, proposalIds, 'time to fork'); dao.escrowToFork(tokenIds, proposalIds, 'time to fork'); } function test_executeFork_reverts() public { - vm.expectRevert(NounsDAOV3Fork.ForkThresholdNotMet.selector); + vm.expectRevert(NounsDAOFork.ForkThresholdNotMet.selector); dao.executeFork(); } function test_joinFork_reverts() public { tokenIds = [4, 5]; - vm.expectRevert(NounsDAOV3Fork.ForkPeriodNotActive.selector); + vm.expectRevert(NounsDAOFork.ForkPeriodNotActive.selector); vm.prank(tokenHolder); dao.joinFork(tokenIds, new uint256[](0), ''); } function test_withdrawDAONounsFromEscrow_onlyAdmin() public { - vm.expectRevert(NounsDAOV3Fork.AdminOnly.selector); + vm.expectRevert(NounsDAOFork.AdminOnly.selector); dao.withdrawDAONounsFromEscrowToTreasury(tokenIds); - vm.expectRevert(NounsDAOV3Fork.AdminOnly.selector); + vm.expectRevert(NounsDAOFork.AdminOnly.selector); dao.withdrawDAONounsFromEscrowIncreasingTotalSupply(tokenIds, address(1)); } @@ -105,7 +101,7 @@ contract DAOForkZeroStateTest is DAOForkZeroState { dao._setForkThresholdBPS(0); assertEq(escrow.numTokensInEscrow(), 0); - vm.expectRevert(NounsDAOV3Fork.ForkThresholdNotMet.selector); + vm.expectRevert(NounsDAOFork.ForkThresholdNotMet.selector); dao.executeFork(); tokenIds = [1]; @@ -134,13 +130,13 @@ abstract contract DAOForkSignaledUnderThresholdState is DAOForkZeroState { contract DAOForkSignaledUnderThresholdStateTest is DAOForkSignaledUnderThresholdState { function test_executeFork_reverts() public { - vm.expectRevert(NounsDAOV3Fork.ForkThresholdNotMet.selector); + vm.expectRevert(NounsDAOFork.ForkThresholdNotMet.selector); dao.executeFork(); } function test_joinFork_reverts() public { tokenIds = [4, 5]; - vm.expectRevert(NounsDAOV3Fork.ForkPeriodNotActive.selector); + vm.expectRevert(NounsDAOFork.ForkPeriodNotActive.selector); vm.prank(tokenHolder); dao.joinFork(tokenIds, new uint256[](0), ''); } @@ -151,7 +147,7 @@ contract DAOForkSignaledUnderThresholdStateTest is DAOForkSignaledUnderThreshold tokenIds = [1, 2, 3]; vm.expectEmit(true, true, true, true); - emit NounsDAOV3Fork.WithdrawFromForkEscrow(escrow.forkId(), tokenHolder, tokenIds); + emit NounsDAOFork.WithdrawFromForkEscrow(escrow.forkId(), tokenHolder, tokenIds); vm.prank(tokenHolder); dao.withdrawFromForkEscrow(tokenIds); @@ -208,7 +204,7 @@ contract DAOForkSignaledOverThresholdStateTest is DAOForkSignaledOverThresholdSt vm.prank(address(dao.timelock())); dao._setForkThresholdBPS(3_000); // 30% - vm.expectRevert(NounsDAOV3Fork.ForkThresholdNotMet.selector); + vm.expectRevert(NounsDAOFork.ForkThresholdNotMet.selector); dao.executeFork(); // adjustedTotalSupply = 20 @@ -223,7 +219,7 @@ contract DAOForkSignaledOverThresholdStateTest is DAOForkSignaledOverThresholdSt function test_joinFork_reverts() public { tokenIds = [6, 7]; - vm.expectRevert(NounsDAOV3Fork.ForkPeriodNotActive.selector); + vm.expectRevert(NounsDAOFork.ForkPeriodNotActive.selector); vm.prank(tokenHolder); dao.joinFork(tokenIds, new uint256[](0), ''); } @@ -237,7 +233,7 @@ contract DAOForkSignaledOverThresholdStateTest is DAOForkSignaledOverThresholdSt vm.expectEmit(true, true, true, true); emit ERC20Sent(address(forkDAODeployer.mockTreasury()), address(erc20Mock), 75 ether); vm.expectEmit(true, true, true, true); - emit NounsDAOV3Fork.ExecuteFork( + emit NounsDAOFork.ExecuteFork( 0, forkDAODeployer.mockTreasury(), forkDAODeployer.mockToken(), @@ -274,7 +270,7 @@ contract DAOForkSignaledOverThresholdStateTest is DAOForkSignaledOverThresholdSt vm.prank(tokenHolder); dao.withdrawFromForkEscrow(tokenIds); - vm.expectRevert(NounsDAOV3Fork.ForkThresholdNotMet.selector); + vm.expectRevert(NounsDAOFork.ForkThresholdNotMet.selector); dao.executeFork(); } @@ -325,20 +321,20 @@ contract DAOForkExecutedStateTest is DAOForkExecutedState { function test_signalFork_reverts() public { tokenIds = [8, 9]; - vm.expectRevert(NounsDAOV3Fork.ForkPeriodActive.selector); + vm.expectRevert(NounsDAOFork.ForkPeriodActive.selector); vm.prank(tokenHolder); dao.escrowToFork(tokenIds, new uint256[](0), ''); } function test_executeFork_reverts() public { - vm.expectRevert(NounsDAOV3Fork.ForkPeriodActive.selector); + vm.expectRevert(NounsDAOFork.ForkPeriodActive.selector); dao.executeFork(); } function test_unsignalFork_reverts() public { tokenIds = [4, 5]; - vm.expectRevert(NounsDAOV3Fork.ForkPeriodActive.selector); + vm.expectRevert(NounsDAOFork.ForkPeriodActive.selector); vm.prank(tokenHolder); dao.withdrawFromForkEscrow(tokenIds); } @@ -348,7 +344,7 @@ contract DAOForkExecutedStateTest is DAOForkExecutedState { proposalIds = [1, 2]; vm.expectEmit(true, true, true, true); - emit NounsDAOV3Fork.JoinFork(escrow.forkId() - 1, tokenHolder, tokenIds, proposalIds, 'some reason'); + emit NounsDAOFork.JoinFork(escrow.forkId() - 1, tokenHolder, tokenIds, proposalIds, 'some reason'); vm.prank(tokenHolder); dao.joinFork(tokenIds, proposalIds, 'some reason'); @@ -385,7 +381,7 @@ contract DAOForkExecutedStateTest is DAOForkExecutedState { tokenIds = [1, 2, 3]; vm.prank(address(dao.timelock())); vm.expectEmit(true, true, true, true); - emit NounsDAOV3Fork.DAONounsSupplyIncreasedFromEscrow(3, address(1)); + emit NounsDAOFork.DAONounsSupplyIncreasedFromEscrow(3, address(1)); dao.withdrawDAONounsFromEscrowIncreasingTotalSupply(tokenIds, address(1)); assertEq(dao.nouns().ownerOf(1), address(1)); @@ -417,12 +413,12 @@ contract DAOForkExecutedActivePeriodOverStateTest is DAOForkExecutedActivePeriod tokenIds = [8, 9]; vm.prank(tokenHolder); - vm.expectRevert(NounsDAOV3Fork.ForkPeriodNotActive.selector); + vm.expectRevert(NounsDAOFork.ForkPeriodNotActive.selector); dao.joinFork(tokenIds, new uint256[](0), ''); } function test_execute_reverts() public { - vm.expectRevert(NounsDAOV3Fork.ForkThresholdNotMet.selector); + vm.expectRevert(NounsDAOFork.ForkThresholdNotMet.selector); dao.executeFork(); } @@ -463,13 +459,13 @@ abstract contract DAOSecondForkSignaledUnderThreshold is DAOForkExecutedActivePe contract DAOSecondForkSignaledUnderThresholdTest is DAOSecondForkSignaledUnderThreshold { function test_executeFork_reverts() public { - vm.expectRevert(NounsDAOV3Fork.ForkThresholdNotMet.selector); + vm.expectRevert(NounsDAOFork.ForkThresholdNotMet.selector); dao.executeFork(); } function test_joinFork_reverts() public { tokenIds = [14, 15]; - vm.expectRevert(NounsDAOV3Fork.ForkPeriodNotActive.selector); + vm.expectRevert(NounsDAOFork.ForkPeriodNotActive.selector); vm.prank(tokenHolder); dao.joinFork(tokenIds, new uint256[](0), ''); } diff --git a/packages/nouns-contracts/test/foundry/NounsDAOLogicV3/NounsDAOLogicV3BaseTest.sol b/packages/nouns-contracts/test/foundry/NounsDAOLogic/NounsDAOLogicBaseTest.sol similarity index 83% rename from packages/nouns-contracts/test/foundry/NounsDAOLogicV3/NounsDAOLogicV3BaseTest.sol rename to packages/nouns-contracts/test/foundry/NounsDAOLogic/NounsDAOLogicBaseTest.sol index 0aba1f9931..bb714a0dcb 100644 --- a/packages/nouns-contracts/test/foundry/NounsDAOLogicV3/NounsDAOLogicV3BaseTest.sol +++ b/packages/nouns-contracts/test/foundry/NounsDAOLogic/NounsDAOLogicBaseTest.sol @@ -5,17 +5,17 @@ import 'forge-std/Test.sol'; import { DeployUtilsV3 } from '../helpers/DeployUtilsV3.sol'; import { SigUtils, ERC1271Stub } from '../helpers/SigUtils.sol'; import { ProxyRegistryMock } from '../helpers/ProxyRegistryMock.sol'; -import { NounsDAOLogicV3 } from '../../../contracts/governance/NounsDAOLogicV3.sol'; -import { NounsDAOV3Proposals } from '../../../contracts/governance/NounsDAOV3Proposals.sol'; +import { NounsDAOProposals } from '../../../contracts/governance/NounsDAOProposals.sol'; import { NounsDAOProxyV3 } from '../../../contracts/governance/NounsDAOProxyV3.sol'; -import { NounsDAOStorageV3 } from '../../../contracts/governance/NounsDAOInterfaces.sol'; +import { NounsDAOTypes } from '../../../contracts/governance/NounsDAOInterfaces.sol'; import { NounsToken } from '../../../contracts/NounsToken.sol'; import { NounsSeeder } from '../../../contracts/NounsSeeder.sol'; import { IProxyRegistry } from '../../../contracts/external/opensea/IProxyRegistry.sol'; import { NounsDAOExecutorV2 } from '../../../contracts/governance/NounsDAOExecutorV2.sol'; import { NounsDAOForkEscrow } from '../../../contracts/governance/fork/NounsDAOForkEscrow.sol'; +import { INounsDAOLogic } from '../../../contracts/interfaces/INounsDAOLogic.sol'; -abstract contract NounsDAOLogicV3BaseTest is Test, DeployUtilsV3, SigUtils { +abstract contract NounsDAOLogicBaseTest is Test, DeployUtilsV3, SigUtils { event ProposalUpdated( uint256 indexed id, address indexed proposer, @@ -58,22 +58,15 @@ abstract contract NounsDAOLogicV3BaseTest is Test, DeployUtilsV3, SigUtils { event ProposalCreatedWithRequirements( uint256 id, - address proposer, address[] signers, - address[] targets, - uint256[] values, - string[] signatures, - bytes[] calldatas, - uint256 startBlock, - uint256 endBlock, uint256 updatePeriodEndBlock, uint256 proposalThreshold, uint256 quorumVotes, - string description + uint32 indexed clientId ); NounsToken nounsToken; - NounsDAOLogicV3 dao; + INounsDAOLogic dao; NounsDAOExecutorV2 timelock; address noundersDAO = makeAddr('nounders'); @@ -100,6 +93,27 @@ abstract contract NounsDAOLogicV3BaseTest is Test, DeployUtilsV3, SigUtils { vm.roll(block.number + 1); } + function propose( + address proposer, + address target, + uint256 value, + string memory signature, + bytes memory data, + string memory description, + uint32 clientId + ) internal returns (uint256 proposalId) { + vm.prank(proposer); + address[] memory targets = new address[](1); + targets[0] = target; + uint256[] memory values = new uint256[](1); + values[0] = value; + string[] memory signatures = new string[](1); + signatures[0] = signature; + bytes[] memory calldatas = new bytes[](1); + calldatas[0] = data; + proposalId = dao.propose(targets, values, signatures, calldatas, description, clientId); + } + function propose( address proposer, address target, @@ -179,7 +193,7 @@ abstract contract NounsDAOLogicV3BaseTest is Test, DeployUtilsV3, SigUtils { address proposer, address signer, uint256 signerPK, - NounsDAOV3Proposals.ProposalTxs memory txs, + NounsDAOProposals.ProposalTxs memory txs, string memory description, uint256 expirationTimestamp ) internal returns (uint256 proposalId) { @@ -198,12 +212,12 @@ abstract contract NounsDAOLogicV3BaseTest is Test, DeployUtilsV3, SigUtils { address[] memory signers, uint256[] memory signerPKs, uint256[] memory expirationTimestamps, - NounsDAOV3Proposals.ProposalTxs memory txs, + NounsDAOProposals.ProposalTxs memory txs, string memory description ) internal returns (uint256 proposalId) { - NounsDAOStorageV3.ProposerSignature[] memory sigs = new NounsDAOStorageV3.ProposerSignature[](signers.length); + NounsDAOTypes.ProposerSignature[] memory sigs = new NounsDAOTypes.ProposerSignature[](signers.length); for (uint256 i = 0; i < signers.length; ++i) { - sigs[i] = NounsDAOStorageV3.ProposerSignature( + sigs[i] = NounsDAOTypes.ProposerSignature( signProposal(proposer, signerPKs[i], txs, description, expirationTimestamps[i], address(dao)), signers[i], expirationTimestamps[i] @@ -220,12 +234,12 @@ abstract contract NounsDAOLogicV3BaseTest is Test, DeployUtilsV3, SigUtils { address[] memory signers, uint256[] memory signerPKs, uint256[] memory expirationTimestamps, - NounsDAOV3Proposals.ProposalTxs memory txs, + NounsDAOProposals.ProposalTxs memory txs, string memory description ) internal { - NounsDAOStorageV3.ProposerSignature[] memory sigs = new NounsDAOStorageV3.ProposerSignature[](signers.length); + NounsDAOTypes.ProposerSignature[] memory sigs = new NounsDAOTypes.ProposerSignature[](signers.length); for (uint256 i = 0; i < signers.length; ++i) { - sigs[i] = NounsDAOStorageV3.ProposerSignature( + sigs[i] = NounsDAOTypes.ProposerSignature( signProposal(proposer, signerPKs[i], txs, description, expirationTimestamps[i], address(dao)), signers[i], expirationTimestamps[i] @@ -250,7 +264,7 @@ abstract contract NounsDAOLogicV3BaseTest is Test, DeployUtilsV3, SigUtils { uint256 value, string memory signature, bytes memory data - ) internal pure returns (NounsDAOV3Proposals.ProposalTxs memory) { + ) internal pure returns (NounsDAOProposals.ProposalTxs memory) { address[] memory targets = new address[](1); targets[0] = target; uint256[] memory values = new uint256[](1); @@ -259,11 +273,11 @@ abstract contract NounsDAOLogicV3BaseTest is Test, DeployUtilsV3, SigUtils { signatures[0] = signature; bytes[] memory calldatas = new bytes[](1); calldatas[0] = data; - return NounsDAOV3Proposals.ProposalTxs(targets, values, signatures, calldatas); + return NounsDAOProposals.ProposalTxs(targets, values, signatures, calldatas); } function expectNewPropEvents( - NounsDAOV3Proposals.ProposalTxs memory txs, + NounsDAOProposals.ProposalTxs memory txs, address expectedProposer, uint256 expectedPropId, uint256 expectedPropThreshold, @@ -289,18 +303,11 @@ abstract contract NounsDAOLogicV3BaseTest is Test, DeployUtilsV3, SigUtils { vm.expectEmit(true, true, true, true); emit ProposalCreatedWithRequirements( expectedPropId, - expectedProposer, expectedSigners, - txs.targets, - txs.values, - txs.signatures, - txs.calldatas, - expectedStartBlock, - expectedEndBlock, block.number + proposalUpdatablePeriodInBlocks, expectedPropThreshold, expectedMinQuorumVotes, - 'description' + 0 // clientId ); } } diff --git a/packages/nouns-contracts/test/foundry/NounsDAOLogicV3/NounsDAOV3Votes.t.sol b/packages/nouns-contracts/test/foundry/NounsDAOLogic/NounsDAOVotes.t.sol similarity index 75% rename from packages/nouns-contracts/test/foundry/NounsDAOLogicV3/NounsDAOV3Votes.t.sol rename to packages/nouns-contracts/test/foundry/NounsDAOLogic/NounsDAOVotes.t.sol index 58f5e8c66c..ad3dbb7489 100644 --- a/packages/nouns-contracts/test/foundry/NounsDAOLogicV3/NounsDAOV3Votes.t.sol +++ b/packages/nouns-contracts/test/foundry/NounsDAOLogic/NounsDAOVotes.t.sol @@ -2,11 +2,11 @@ pragma solidity ^0.8.15; import 'forge-std/Test.sol'; -import { NounsDAOLogicV3BaseTest } from './NounsDAOLogicV3BaseTest.sol'; -import { NounsDAOV3Votes } from '../../../contracts/governance/NounsDAOV3Votes.sol'; -import { NounsDAOStorageV3 } from '../../../contracts/governance/NounsDAOInterfaces.sol'; +import { NounsDAOLogicBaseTest } from './NounsDAOLogicBaseTest.sol'; +import { NounsDAOVotes } from '../../../contracts/governance/NounsDAOVotes.sol'; +import { NounsDAOTypes } from '../../../contracts/governance/NounsDAOInterfaces.sol'; -contract NounsDAOLogicV3VotesTest is NounsDAOLogicV3BaseTest { +contract NounsDAOLogicVotesTest is NounsDAOLogicBaseTest { address proposer = makeAddr('proposer'); address voter = makeAddr('voter'); uint256 proposalId; @@ -39,16 +39,16 @@ contract NounsDAOLogicV3VotesTest is NounsDAOLogicV3BaseTest { // go into objection period vm.roll(block.number + dao.lastMinuteWindowInBlocks()); - assertTrue(dao.state(proposalId) == NounsDAOStorageV3.ProposalState.ObjectionPeriod); + assertTrue(dao.state(proposalId) == NounsDAOTypes.ProposalState.ObjectionPeriod); - vm.expectRevert(NounsDAOV3Votes.CanOnlyVoteAgainstDuringObjectionPeriod.selector); + vm.expectRevert(NounsDAOVotes.CanOnlyVoteAgainstDuringObjectionPeriod.selector); vm.prank(voter); dao.castVote(proposalId, 1); } function test_givenStateUpdatable_reverts() public { vm.startPrank(voter); - assertTrue(dao.state(proposalId) == NounsDAOStorageV3.ProposalState.Updatable); + assertTrue(dao.state(proposalId) == NounsDAOTypes.ProposalState.Updatable); vm.expectRevert('NounsDAO::castVoteInternal: voting is closed'); dao.castVote(proposalId, 1); @@ -58,7 +58,7 @@ contract NounsDAOLogicV3VotesTest is NounsDAOLogicV3BaseTest { vm.startPrank(voter); vm.roll(block.number + dao.proposalUpdatablePeriodInBlocks() + 1); - assertTrue(dao.state(proposalId) == NounsDAOStorageV3.ProposalState.Pending); + assertTrue(dao.state(proposalId) == NounsDAOTypes.ProposalState.Pending); vm.expectRevert('NounsDAO::castVoteInternal: voting is closed'); dao.castVote(proposalId, 1); @@ -68,7 +68,7 @@ contract NounsDAOLogicV3VotesTest is NounsDAOLogicV3BaseTest { vm.startPrank(voter); vm.roll(block.number + dao.proposalUpdatablePeriodInBlocks() + dao.votingDelay() + dao.votingPeriod() + 1); - assertTrue(dao.state(proposalId) == NounsDAOStorageV3.ProposalState.Defeated); + assertTrue(dao.state(proposalId) == NounsDAOTypes.ProposalState.Defeated); vm.expectRevert('NounsDAO::castVoteInternal: voting is closed'); dao.castVote(proposalId, 1); @@ -78,12 +78,12 @@ contract NounsDAOLogicV3VotesTest is NounsDAOLogicV3BaseTest { vm.startPrank(voter); vm.roll(block.number + dao.proposalUpdatablePeriodInBlocks() + dao.votingDelay() + 1); - assertTrue(dao.state(proposalId) == NounsDAOStorageV3.ProposalState.Active); + assertTrue(dao.state(proposalId) == NounsDAOTypes.ProposalState.Active); dao.castVote(proposalId, 1); vm.roll(block.number + dao.votingPeriod()); - assertTrue(dao.state(proposalId) == NounsDAOStorageV3.ProposalState.Succeeded); + assertTrue(dao.state(proposalId) == NounsDAOTypes.ProposalState.Succeeded); vm.expectRevert('NounsDAO::castVoteInternal: voting is closed'); dao.castVote(proposalId, 1); diff --git a/packages/nouns-contracts/test/foundry/NounsDAOLogic/Propose.t.sol b/packages/nouns-contracts/test/foundry/NounsDAOLogic/Propose.t.sol new file mode 100644 index 0000000000..bc641d7c4c --- /dev/null +++ b/packages/nouns-contracts/test/foundry/NounsDAOLogic/Propose.t.sol @@ -0,0 +1,200 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity ^0.8.15; + +import 'forge-std/Test.sol'; +import { NounsDAOLogicBaseTest } from './NounsDAOLogicBaseTest.sol'; +import { NounsDAOTypes } from '../../../contracts/governance/NounsDAOInterfaces.sol'; + +contract ProposeTest is NounsDAOLogicBaseTest { + address proposer = makeAddr('proposer'); + + function setUp() public override { + super.setUp(); + + vm.prank(address(dao.timelock())); + dao._setProposalThresholdBPS(1_000); + + for (uint256 i = 0; i < 10; i++) { + mintTo(proposer); + } + } + + function testEmits_ProposalCreated_and_ProposalCreatedWithRequirements() public { + address[] memory targets = new address[](1); + targets[0] = makeAddr('target'); + uint256[] memory values = new uint256[](1); + values[0] = 42; + string[] memory signatures = new string[](1); + signatures[0] = 'some signature'; + bytes[] memory calldatas = new bytes[](1); + calldatas[0] = ''; + + uint256 updatablePeriodEndBlock = block.number + dao.proposalUpdatablePeriodInBlocks(); + uint256 startBlock = updatablePeriodEndBlock + dao.votingDelay(); + uint256 endBlock = startBlock + dao.votingPeriod(); + + vm.expectEmit(true, true, true, true); + emit ProposalCreated( + 1, + proposer, + targets, + values, + signatures, + calldatas, + startBlock, + endBlock, + 'some description' + ); + + vm.expectEmit(true, true, true, true); + emit ProposalCreatedWithRequirements( + 1, + new address[](0), + updatablePeriodEndBlock, + 1, // prop threshold + dao.minQuorumVotes(), + 0 // clientId + ); + + vm.prank(proposer); + + dao.propose(targets, values, signatures, calldatas, 'some description'); + } +} + +contract ProposalDataForRewardsTest is NounsDAOLogicBaseTest { + address proposer = makeAddr('proposer'); + address voter = makeAddr('voter'); + + function setUp() public override { + super.setUp(); + + vm.prank(address(dao.timelock())); + dao._setProposalThresholdBPS(1_000); + + for (uint256 i = 0; i < 10; i++) { + mintTo(proposer); + } + + for (uint256 i = 0; i < 3; i++) { + mintTo(voter); + } + } + + function test_returnsData() public { + uint256 proposalId = propose(proposer, address(1), 0, '', '', 'proposal', 123); + uint32[] memory emptyArray = new uint32[](0); + + NounsDAOTypes.ProposalForRewards[] memory data = dao.proposalDataForRewards({ + firstProposalId: proposalId, + lastProposalId: proposalId, + proposalEligibilityQuorumBps: 0, + excludeCanceled: false, + requireVotingEnded: false, + votingClientIds: emptyArray + }); + + assertEq(data[0].clientId, 123); + assertEq(data[0].creationTimestamp, block.timestamp); + } + + function test_excludesCanceledProposalsIfFlagIsOn() public { + uint256 proposalId = propose(proposer, address(1), 0, '', '', 'proposal', 123); + + vm.prank(proposer); + dao.cancel(proposalId); + + uint32[] memory emptyArray = new uint32[](0); + NounsDAOTypes.ProposalForRewards[] memory data = dao.proposalDataForRewards({ + firstProposalId: proposalId, + lastProposalId: proposalId, + proposalEligibilityQuorumBps: 0, + excludeCanceled: true, + requireVotingEnded: false, + votingClientIds: emptyArray + }); + + assertEq(data.length, 0); + } + + function test_requireVotingEnded_revertsIfVotingNotEnded() public { + uint256 proposalId = propose(proposer, address(1), 0, '', '', 'proposal', 123); + + uint32[] memory emptyArray = new uint32[](0); + vm.expectRevert('all proposals must be done with voting'); + dao.proposalDataForRewards({ + firstProposalId: proposalId, + lastProposalId: proposalId, + proposalEligibilityQuorumBps: 0, + excludeCanceled: true, + requireVotingEnded: true, + votingClientIds: emptyArray + }); + } + + function test_requireVotingEnded_doesntRevertIfVotingEnded() public { + uint256 proposalId = propose(proposer, address(1), 0, '', '', 'proposal', 123); + + vm.roll(dao.proposals(proposalId).endBlock + 1); + + uint32[] memory emptyArray = new uint32[](0); + dao.proposalDataForRewards({ + firstProposalId: proposalId, + lastProposalId: proposalId, + proposalEligibilityQuorumBps: 0, + excludeCanceled: true, + requireVotingEnded: true, + votingClientIds: emptyArray + }); + } + + function test_includesCanceledProposalsIfFlagIsOff() public { + uint256 proposalId = propose(proposer, address(1), 0, '', '', 'proposal', 123); + + vm.prank(proposer); + dao.cancel(proposalId); + + uint32[] memory emptyArray = new uint32[](0); + NounsDAOTypes.ProposalForRewards[] memory data = dao.proposalDataForRewards({ + firstProposalId: proposalId, + lastProposalId: proposalId, + proposalEligibilityQuorumBps: 0, + excludeCanceled: false, + requireVotingEnded: false, + votingClientIds: emptyArray + }); + + assertEq(data.length, 1); + } + + function test_filtersProposalsBasedOnQuorum() public { + uint256 proposalId = propose(proposer, address(1), 0, '', '', 'proposal', 123); + + uint32[] memory emptyArray = new uint32[](0); + NounsDAOTypes.ProposalForRewards[] memory data = dao.proposalDataForRewards({ + firstProposalId: proposalId, + lastProposalId: proposalId, + proposalEligibilityQuorumBps: 2000, + excludeCanceled: false, + requireVotingEnded: false, + votingClientIds: emptyArray + }); + + assertEq(data.length, 0); + + vm.roll(dao.proposals(proposalId).startBlock + 1); + vm.prank(voter); + dao.castRefundableVote(proposalId, 1); + + data = dao.proposalDataForRewards({ + firstProposalId: proposalId, + lastProposalId: proposalId, + proposalEligibilityQuorumBps: 2000, + excludeCanceled: false, + requireVotingEnded: false, + votingClientIds: emptyArray + }); + + assertEq(data.length, 1); + } +} diff --git a/packages/nouns-contracts/test/foundry/NounsDAOLogicV3/ProposeBySigs.t.sol b/packages/nouns-contracts/test/foundry/NounsDAOLogic/ProposeBySigs.t.sol similarity index 66% rename from packages/nouns-contracts/test/foundry/NounsDAOLogicV3/ProposeBySigs.t.sol rename to packages/nouns-contracts/test/foundry/NounsDAOLogic/ProposeBySigs.t.sol index 3a814cb20f..612a20cea1 100644 --- a/packages/nouns-contracts/test/foundry/NounsDAOLogicV3/ProposeBySigs.t.sol +++ b/packages/nouns-contracts/test/foundry/NounsDAOLogic/ProposeBySigs.t.sol @@ -2,19 +2,18 @@ pragma solidity ^0.8.15; import 'forge-std/Test.sol'; -import { NounsDAOLogicV3BaseTest } from './NounsDAOLogicV3BaseTest.sol'; +import { NounsDAOLogicBaseTest } from './NounsDAOLogicBaseTest.sol'; import { DeployUtils } from '../helpers/DeployUtils.sol'; import { SigUtils, ERC1271Stub } from '../helpers/SigUtils.sol'; -import { NounsDAOLogicV3 } from '../../../contracts/governance/NounsDAOLogicV3.sol'; -import { NounsDAOV3Proposals } from '../../../contracts/governance/NounsDAOV3Proposals.sol'; +import { NounsDAOProposals } from '../../../contracts/governance/NounsDAOProposals.sol'; import { NounsDAOProxyV3 } from '../../../contracts/governance/NounsDAOProxyV3.sol'; -import { NounsDAOStorageV3 } from '../../../contracts/governance/NounsDAOInterfaces.sol'; +import { NounsDAOTypes } from '../../../contracts/governance/NounsDAOInterfaces.sol'; import { NounsToken } from '../../../contracts/NounsToken.sol'; import { NounsSeeder } from '../../../contracts/NounsSeeder.sol'; import { IProxyRegistry } from '../../../contracts/external/opensea/IProxyRegistry.sol'; import { NounsDAOExecutor } from '../../../contracts/governance/NounsDAOExecutor.sol'; -contract ProposeBySigsTest is NounsDAOLogicV3BaseTest { +contract ProposeBySigsTest is NounsDAOLogicBaseTest { address proposerWithVote; uint256 proposerWithVotePK; address proposerWithNoVotes = makeAddr('proposerWithNoVotes'); @@ -48,18 +47,18 @@ contract ProposeBySigsTest is NounsDAOLogicV3BaseTest { } function test_givenNoSigs_reverts() public { - NounsDAOV3Proposals.ProposalTxs memory txs = makeTxs(makeAddr('target'), 0, '', ''); - NounsDAOStorageV3.ProposerSignature[] memory proposerSignatures = new NounsDAOStorageV3.ProposerSignature[](0); + NounsDAOProposals.ProposalTxs memory txs = makeTxs(makeAddr('target'), 0, '', ''); + NounsDAOTypes.ProposerSignature[] memory proposerSignatures = new NounsDAOTypes.ProposerSignature[](0); - vm.expectRevert(abi.encodeWithSelector(NounsDAOV3Proposals.MustProvideSignatures.selector)); + vm.expectRevert(abi.encodeWithSelector(NounsDAOProposals.MustProvideSignatures.selector)); dao.proposeBySigs(proposerSignatures, txs.targets, txs.values, txs.signatures, txs.calldatas, ''); } function test_givenCanceledSig_reverts() public { - NounsDAOV3Proposals.ProposalTxs memory txs = makeTxs(makeAddr('target'), 0, '', ''); + NounsDAOProposals.ProposalTxs memory txs = makeTxs(makeAddr('target'), 0, '', ''); uint256 expirationTimestamp = block.timestamp + 1234; - NounsDAOStorageV3.ProposerSignature[] memory proposerSignatures = new NounsDAOStorageV3.ProposerSignature[](1); - proposerSignatures[0] = NounsDAOStorageV3.ProposerSignature( + NounsDAOTypes.ProposerSignature[] memory proposerSignatures = new NounsDAOTypes.ProposerSignature[](1); + proposerSignatures[0] = NounsDAOTypes.ProposerSignature( signProposal(proposerWithVote, signerWithVote1PK, txs, '', expirationTimestamp, address(dao)), signerWithVote1, expirationTimestamp @@ -68,31 +67,31 @@ contract ProposeBySigsTest is NounsDAOLogicV3BaseTest { vm.prank(signerWithVote1); dao.cancelSig(proposerSignatures[0].sig); - vm.expectRevert(abi.encodeWithSelector(NounsDAOV3Proposals.SignatureIsCancelled.selector)); + vm.expectRevert(abi.encodeWithSelector(NounsDAOProposals.SignatureIsCancelled.selector)); vm.prank(proposerWithVote); dao.proposeBySigs(proposerSignatures, txs.targets, txs.values, txs.signatures, txs.calldatas, ''); } function test_givenExpireddSig_reverts() public { - NounsDAOV3Proposals.ProposalTxs memory txs = makeTxs(makeAddr('target'), 0, '', ''); + NounsDAOProposals.ProposalTxs memory txs = makeTxs(makeAddr('target'), 0, '', ''); uint256 expirationTimestamp = block.timestamp - 1; - NounsDAOStorageV3.ProposerSignature[] memory proposerSignatures = new NounsDAOStorageV3.ProposerSignature[](1); - proposerSignatures[0] = NounsDAOStorageV3.ProposerSignature( + NounsDAOTypes.ProposerSignature[] memory proposerSignatures = new NounsDAOTypes.ProposerSignature[](1); + proposerSignatures[0] = NounsDAOTypes.ProposerSignature( signProposal(proposerWithVote, signerWithVote1PK, txs, '', expirationTimestamp, address(dao)), signerWithVote1, expirationTimestamp ); - vm.expectRevert(abi.encodeWithSelector(NounsDAOV3Proposals.SignatureExpired.selector)); + vm.expectRevert(abi.encodeWithSelector(NounsDAOProposals.SignatureExpired.selector)); vm.prank(proposerWithVote); dao.proposeBySigs(proposerSignatures, txs.targets, txs.values, txs.signatures, txs.calldatas, ''); } function test_givenSigOnDifferentDescription_reverts() public { - NounsDAOV3Proposals.ProposalTxs memory txs = makeTxs(makeAddr('target'), 0, '', ''); + NounsDAOProposals.ProposalTxs memory txs = makeTxs(makeAddr('target'), 0, '', ''); uint256 expirationTimestamp = block.timestamp + 1234; - NounsDAOStorageV3.ProposerSignature[] memory proposerSignatures = new NounsDAOStorageV3.ProposerSignature[](1); - proposerSignatures[0] = NounsDAOStorageV3.ProposerSignature( + NounsDAOTypes.ProposerSignature[] memory proposerSignatures = new NounsDAOTypes.ProposerSignature[](1); + proposerSignatures[0] = NounsDAOTypes.ProposerSignature( signProposal( proposerWithVote, signerWithVote1PK, @@ -105,7 +104,7 @@ contract ProposeBySigsTest is NounsDAOLogicV3BaseTest { expirationTimestamp ); - vm.expectRevert(abi.encodeWithSelector(NounsDAOV3Proposals.InvalidSignature.selector)); + vm.expectRevert(abi.encodeWithSelector(NounsDAOProposals.InvalidSignature.selector)); vm.prank(proposerWithVote); dao.proposeBySigs( proposerSignatures, @@ -118,10 +117,10 @@ contract ProposeBySigsTest is NounsDAOLogicV3BaseTest { } function test_givenSigOnDifferentTargets_reverts() public { - NounsDAOV3Proposals.ProposalTxs memory txs = makeTxs(makeAddr('target'), 0, '', ''); + NounsDAOProposals.ProposalTxs memory txs = makeTxs(makeAddr('target'), 0, '', ''); uint256 expirationTimestamp = block.timestamp + 1234; - NounsDAOStorageV3.ProposerSignature[] memory proposerSignatures = new NounsDAOStorageV3.ProposerSignature[](1); - proposerSignatures[0] = NounsDAOStorageV3.ProposerSignature( + NounsDAOTypes.ProposerSignature[] memory proposerSignatures = new NounsDAOTypes.ProposerSignature[](1); + proposerSignatures[0] = NounsDAOTypes.ProposerSignature( signProposal(proposerWithVote, signerWithVote1PK, txs, 'description', expirationTimestamp, address(dao)), signerWithVote1, expirationTimestamp @@ -129,16 +128,16 @@ contract ProposeBySigsTest is NounsDAOLogicV3BaseTest { txs.targets[0] = makeAddr('different target'); - vm.expectRevert(abi.encodeWithSelector(NounsDAOV3Proposals.InvalidSignature.selector)); + vm.expectRevert(abi.encodeWithSelector(NounsDAOProposals.InvalidSignature.selector)); vm.prank(proposerWithVote); dao.proposeBySigs(proposerSignatures, txs.targets, txs.values, txs.signatures, txs.calldatas, 'description'); } function test_givenSigOnDifferentValues_reverts() public { - NounsDAOV3Proposals.ProposalTxs memory txs = makeTxs(makeAddr('target'), 0, '', ''); + NounsDAOProposals.ProposalTxs memory txs = makeTxs(makeAddr('target'), 0, '', ''); uint256 expirationTimestamp = block.timestamp + 1234; - NounsDAOStorageV3.ProposerSignature[] memory proposerSignatures = new NounsDAOStorageV3.ProposerSignature[](1); - proposerSignatures[0] = NounsDAOStorageV3.ProposerSignature( + NounsDAOTypes.ProposerSignature[] memory proposerSignatures = new NounsDAOTypes.ProposerSignature[](1); + proposerSignatures[0] = NounsDAOTypes.ProposerSignature( signProposal(proposerWithVote, signerWithVote1PK, txs, 'description', expirationTimestamp, address(dao)), signerWithVote1, expirationTimestamp @@ -146,16 +145,16 @@ contract ProposeBySigsTest is NounsDAOLogicV3BaseTest { txs.values[0] = 42; - vm.expectRevert(abi.encodeWithSelector(NounsDAOV3Proposals.InvalidSignature.selector)); + vm.expectRevert(abi.encodeWithSelector(NounsDAOProposals.InvalidSignature.selector)); vm.prank(proposerWithVote); dao.proposeBySigs(proposerSignatures, txs.targets, txs.values, txs.signatures, txs.calldatas, 'description'); } function test_givenSigOnDifferentSignatures_reverts() public { - NounsDAOV3Proposals.ProposalTxs memory txs = makeTxs(makeAddr('target'), 0, '', ''); + NounsDAOProposals.ProposalTxs memory txs = makeTxs(makeAddr('target'), 0, '', ''); uint256 expirationTimestamp = block.timestamp + 1234; - NounsDAOStorageV3.ProposerSignature[] memory proposerSignatures = new NounsDAOStorageV3.ProposerSignature[](1); - proposerSignatures[0] = NounsDAOStorageV3.ProposerSignature( + NounsDAOTypes.ProposerSignature[] memory proposerSignatures = new NounsDAOTypes.ProposerSignature[](1); + proposerSignatures[0] = NounsDAOTypes.ProposerSignature( signProposal(proposerWithVote, signerWithVote1PK, txs, 'description', expirationTimestamp, address(dao)), signerWithVote1, expirationTimestamp @@ -163,16 +162,16 @@ contract ProposeBySigsTest is NounsDAOLogicV3BaseTest { txs.signatures[0] = 'different signature'; - vm.expectRevert(abi.encodeWithSelector(NounsDAOV3Proposals.InvalidSignature.selector)); + vm.expectRevert(abi.encodeWithSelector(NounsDAOProposals.InvalidSignature.selector)); vm.prank(proposerWithVote); dao.proposeBySigs(proposerSignatures, txs.targets, txs.values, txs.signatures, txs.calldatas, 'description'); } function test_givenSigOnDifferentCalldatas_reverts() public { - NounsDAOV3Proposals.ProposalTxs memory txs = makeTxs(makeAddr('target'), 0, '', ''); + NounsDAOProposals.ProposalTxs memory txs = makeTxs(makeAddr('target'), 0, '', ''); uint256 expirationTimestamp = block.timestamp + 1234; - NounsDAOStorageV3.ProposerSignature[] memory proposerSignatures = new NounsDAOStorageV3.ProposerSignature[](1); - proposerSignatures[0] = NounsDAOStorageV3.ProposerSignature( + NounsDAOTypes.ProposerSignature[] memory proposerSignatures = new NounsDAOTypes.ProposerSignature[](1); + proposerSignatures[0] = NounsDAOTypes.ProposerSignature( signProposal(proposerWithVote, signerWithVote1PK, txs, 'description', expirationTimestamp, address(dao)), signerWithVote1, expirationTimestamp @@ -180,16 +179,16 @@ contract ProposeBySigsTest is NounsDAOLogicV3BaseTest { txs.calldatas[0] = 'different calldatas'; - vm.expectRevert(abi.encodeWithSelector(NounsDAOV3Proposals.InvalidSignature.selector)); + vm.expectRevert(abi.encodeWithSelector(NounsDAOProposals.InvalidSignature.selector)); vm.prank(proposerWithVote); dao.proposeBySigs(proposerSignatures, txs.targets, txs.values, txs.signatures, txs.calldatas, 'description'); } function test_givenSigOnDifferentExpiration_reverts() public { - NounsDAOV3Proposals.ProposalTxs memory txs = makeTxs(makeAddr('target'), 0, '', ''); + NounsDAOProposals.ProposalTxs memory txs = makeTxs(makeAddr('target'), 0, '', ''); uint256 expirationTimestamp = block.timestamp + 1234; - NounsDAOStorageV3.ProposerSignature[] memory proposerSignatures = new NounsDAOStorageV3.ProposerSignature[](1); - proposerSignatures[0] = NounsDAOStorageV3.ProposerSignature( + NounsDAOTypes.ProposerSignature[] memory proposerSignatures = new NounsDAOTypes.ProposerSignature[](1); + proposerSignatures[0] = NounsDAOTypes.ProposerSignature( signProposal(proposerWithVote, signerWithVote1PK, txs, 'description', expirationTimestamp, address(dao)), signerWithVote1, expirationTimestamp @@ -197,16 +196,16 @@ contract ProposeBySigsTest is NounsDAOLogicV3BaseTest { proposerSignatures[0].expirationTimestamp = expirationTimestamp + 1; - vm.expectRevert(abi.encodeWithSelector(NounsDAOV3Proposals.InvalidSignature.selector)); + vm.expectRevert(abi.encodeWithSelector(NounsDAOProposals.InvalidSignature.selector)); vm.prank(proposerWithVote); dao.proposeBySigs(proposerSignatures, txs.targets, txs.values, txs.signatures, txs.calldatas, 'description'); } function test_givenSigOnDifferentSigner_reverts() public { - NounsDAOV3Proposals.ProposalTxs memory txs = makeTxs(makeAddr('target'), 0, '', ''); + NounsDAOProposals.ProposalTxs memory txs = makeTxs(makeAddr('target'), 0, '', ''); uint256 expirationTimestamp = block.timestamp + 1234; - NounsDAOStorageV3.ProposerSignature[] memory proposerSignatures = new NounsDAOStorageV3.ProposerSignature[](1); - proposerSignatures[0] = NounsDAOStorageV3.ProposerSignature( + NounsDAOTypes.ProposerSignature[] memory proposerSignatures = new NounsDAOTypes.ProposerSignature[](1); + proposerSignatures[0] = NounsDAOTypes.ProposerSignature( signProposal(proposerWithVote, signerWithVote1PK, txs, 'description', expirationTimestamp, address(dao)), signerWithVote1, expirationTimestamp @@ -214,16 +213,16 @@ contract ProposeBySigsTest is NounsDAOLogicV3BaseTest { proposerSignatures[0].signer = makeAddr('different signer than sig'); - vm.expectRevert(abi.encodeWithSelector(NounsDAOV3Proposals.InvalidSignature.selector)); + vm.expectRevert(abi.encodeWithSelector(NounsDAOProposals.InvalidSignature.selector)); vm.prank(proposerWithVote); dao.proposeBySigs(proposerSignatures, txs.targets, txs.values, txs.signatures, txs.calldatas, 'description'); } function test_givenSigOnDifferentDomainName_reverts() public { - NounsDAOV3Proposals.ProposalTxs memory txs = makeTxs(makeAddr('target'), 0, '', ''); + NounsDAOProposals.ProposalTxs memory txs = makeTxs(makeAddr('target'), 0, '', ''); uint256 expirationTimestamp = block.timestamp + 1234; - NounsDAOStorageV3.ProposerSignature[] memory proposerSignatures = new NounsDAOStorageV3.ProposerSignature[](1); - proposerSignatures[0] = NounsDAOStorageV3.ProposerSignature( + NounsDAOTypes.ProposerSignature[] memory proposerSignatures = new NounsDAOTypes.ProposerSignature[](1); + proposerSignatures[0] = NounsDAOTypes.ProposerSignature( signProposal( proposerWithVote, signerWithVote1PK, @@ -237,16 +236,16 @@ contract ProposeBySigsTest is NounsDAOLogicV3BaseTest { expirationTimestamp ); - vm.expectRevert(abi.encodeWithSelector(NounsDAOV3Proposals.InvalidSignature.selector)); + vm.expectRevert(abi.encodeWithSelector(NounsDAOProposals.InvalidSignature.selector)); vm.prank(proposerWithVote); dao.proposeBySigs(proposerSignatures, txs.targets, txs.values, txs.signatures, txs.calldatas, 'description'); } function test_givenSigOnDifferentVerifyingContract_reverts() public { - NounsDAOV3Proposals.ProposalTxs memory txs = makeTxs(makeAddr('target'), 0, '', ''); + NounsDAOProposals.ProposalTxs memory txs = makeTxs(makeAddr('target'), 0, '', ''); uint256 expirationTimestamp = block.timestamp + 1234; - NounsDAOStorageV3.ProposerSignature[] memory proposerSignatures = new NounsDAOStorageV3.ProposerSignature[](1); - proposerSignatures[0] = NounsDAOStorageV3.ProposerSignature( + NounsDAOTypes.ProposerSignature[] memory proposerSignatures = new NounsDAOTypes.ProposerSignature[](1); + proposerSignatures[0] = NounsDAOTypes.ProposerSignature( signProposal( proposerWithVote, signerWithVote1PK, @@ -259,24 +258,24 @@ contract ProposeBySigsTest is NounsDAOLogicV3BaseTest { expirationTimestamp ); - vm.expectRevert(abi.encodeWithSelector(NounsDAOV3Proposals.InvalidSignature.selector)); + vm.expectRevert(abi.encodeWithSelector(NounsDAOProposals.InvalidSignature.selector)); vm.prank(proposerWithVote); dao.proposeBySigs(proposerSignatures, txs.targets, txs.values, txs.signatures, txs.calldatas, 'description'); } function test_givenERC1271CheckReturnsFalse_reverts() public { ERC1271Stub erc1271 = new ERC1271Stub(); - NounsDAOV3Proposals.ProposalTxs memory txs = makeTxs(makeAddr('target'), 0, '', ''); + NounsDAOProposals.ProposalTxs memory txs = makeTxs(makeAddr('target'), 0, '', ''); uint256 expirationTimestamp = block.timestamp + 1234; - NounsDAOStorageV3.ProposerSignature[] memory proposerSignatures = new NounsDAOStorageV3.ProposerSignature[](1); - proposerSignatures[0] = NounsDAOStorageV3.ProposerSignature( + NounsDAOTypes.ProposerSignature[] memory proposerSignatures = new NounsDAOTypes.ProposerSignature[](1); + proposerSignatures[0] = NounsDAOTypes.ProposerSignature( signProposal(proposerWithVote, signerWithVote1PK, txs, 'description', expirationTimestamp, address(dao)), address(erc1271), expirationTimestamp ); erc1271.setResponse(keccak256(proposerSignatures[0].sig), false); - vm.expectRevert(abi.encodeWithSelector(NounsDAOV3Proposals.InvalidSignature.selector)); + vm.expectRevert(abi.encodeWithSelector(NounsDAOProposals.InvalidSignature.selector)); vm.prank(proposerWithVote); dao.proposeBySigs(proposerSignatures, txs.targets, txs.values, txs.signatures, txs.calldatas, 'description'); } @@ -284,16 +283,16 @@ contract ProposeBySigsTest is NounsDAOLogicV3BaseTest { function test_givenSignerWithAnActiveProp_reverts() public { propose(signerWithVote1, makeAddr('target'), 0, '', '', ''); - NounsDAOV3Proposals.ProposalTxs memory txs = makeTxs(makeAddr('target'), 0, '', ''); + NounsDAOProposals.ProposalTxs memory txs = makeTxs(makeAddr('target'), 0, '', ''); uint256 expirationTimestamp = block.timestamp + 1234; - NounsDAOStorageV3.ProposerSignature[] memory proposerSignatures = new NounsDAOStorageV3.ProposerSignature[](1); - proposerSignatures[0] = NounsDAOStorageV3.ProposerSignature( + NounsDAOTypes.ProposerSignature[] memory proposerSignatures = new NounsDAOTypes.ProposerSignature[](1); + proposerSignatures[0] = NounsDAOTypes.ProposerSignature( signProposal(proposerWithVote, signerWithVote1PK, txs, 'description', expirationTimestamp, address(dao)), signerWithVote1, expirationTimestamp ); - vm.expectRevert(abi.encodeWithSelector(NounsDAOV3Proposals.ProposerAlreadyHasALiveProposal.selector)); + vm.expectRevert(abi.encodeWithSelector(NounsDAOProposals.ProposerAlreadyHasALiveProposal.selector)); vm.prank(proposerWithVote); dao.proposeBySigs(proposerSignatures, txs.targets, txs.values, txs.signatures, txs.calldatas, 'description'); } @@ -301,16 +300,16 @@ contract ProposeBySigsTest is NounsDAOLogicV3BaseTest { function test_givenProposerWithAnActiveProp_reverts() public { propose(proposerWithVote, makeAddr('target'), 0, '', '', ''); - NounsDAOV3Proposals.ProposalTxs memory txs = makeTxs(makeAddr('target'), 0, '', ''); + NounsDAOProposals.ProposalTxs memory txs = makeTxs(makeAddr('target'), 0, '', ''); uint256 expirationTimestamp = block.timestamp + 1234; - NounsDAOStorageV3.ProposerSignature[] memory proposerSignatures = new NounsDAOStorageV3.ProposerSignature[](1); - proposerSignatures[0] = NounsDAOStorageV3.ProposerSignature( + NounsDAOTypes.ProposerSignature[] memory proposerSignatures = new NounsDAOTypes.ProposerSignature[](1); + proposerSignatures[0] = NounsDAOTypes.ProposerSignature( signProposal(proposerWithVote, signerWithVote1PK, txs, 'description', expirationTimestamp, address(dao)), signerWithVote1, expirationTimestamp ); - vm.expectRevert(abi.encodeWithSelector(NounsDAOV3Proposals.ProposerAlreadyHasALiveProposal.selector)); + vm.expectRevert(abi.encodeWithSelector(NounsDAOProposals.ProposerAlreadyHasALiveProposal.selector)); vm.prank(proposerWithVote); dao.proposeBySigs(proposerSignatures, txs.targets, txs.values, txs.signatures, txs.calldatas, 'description'); } @@ -324,31 +323,31 @@ contract ProposeBySigsTest is NounsDAOLogicV3BaseTest { vm.roll(block.number + 1); vm.stopPrank(); - NounsDAOV3Proposals.ProposalTxs memory txs = makeTxs(makeAddr('target'), 0, '', ''); + NounsDAOProposals.ProposalTxs memory txs = makeTxs(makeAddr('target'), 0, '', ''); uint256 expirationTimestamp = block.timestamp + 1234; - NounsDAOStorageV3.ProposerSignature[] memory proposerSignatures = new NounsDAOStorageV3.ProposerSignature[](1); - proposerSignatures[0] = NounsDAOStorageV3.ProposerSignature( + NounsDAOTypes.ProposerSignature[] memory proposerSignatures = new NounsDAOTypes.ProposerSignature[](1); + proposerSignatures[0] = NounsDAOTypes.ProposerSignature( signProposal(proposerWithVote, signerWithVote1PK, txs, 'description', expirationTimestamp, address(dao)), signerWithVote1, expirationTimestamp ); - vm.expectRevert(NounsDAOV3Proposals.VotesBelowProposalThreshold.selector); + vm.expectRevert(NounsDAOProposals.VotesBelowProposalThreshold.selector); vm.prank(proposerWithVote); dao.proposeBySigs(proposerSignatures, txs.targets, txs.values, txs.signatures, txs.calldatas, 'description'); } function test_givenProposerWithEnoughVotesAndSignerWithNoVotes_reverts() public { - NounsDAOV3Proposals.ProposalTxs memory txs = makeTxs(makeAddr('target'), 0, '', ''); + NounsDAOProposals.ProposalTxs memory txs = makeTxs(makeAddr('target'), 0, '', ''); uint256 expirationTimestamp = block.timestamp + 1234; - NounsDAOStorageV3.ProposerSignature[] memory proposerSignatures = new NounsDAOStorageV3.ProposerSignature[](1); - proposerSignatures[0] = NounsDAOStorageV3.ProposerSignature( + NounsDAOTypes.ProposerSignature[] memory proposerSignatures = new NounsDAOTypes.ProposerSignature[](1); + proposerSignatures[0] = NounsDAOTypes.ProposerSignature( signProposal(proposerWithVote, signerWithNoVotesPK, txs, 'description', expirationTimestamp, address(dao)), signerWithNoVotes, expirationTimestamp ); - vm.expectRevert(NounsDAOV3Proposals.MustProvideSignatures.selector); + vm.expectRevert(NounsDAOProposals.MustProvideSignatures.selector); vm.prank(proposerWithVote); dao.proposeBySigs(proposerSignatures, txs.targets, txs.values, txs.signatures, txs.calldatas, 'description'); } @@ -362,10 +361,10 @@ contract ProposeBySigsTest is NounsDAOLogicV3BaseTest { vm.roll(block.number + 1); vm.stopPrank(); - NounsDAOV3Proposals.ProposalTxs memory txs = makeTxs(makeAddr('target'), 0, '', ''); + NounsDAOProposals.ProposalTxs memory txs = makeTxs(makeAddr('target'), 0, '', ''); uint256 expirationTimestamp = block.timestamp + 1234; - NounsDAOStorageV3.ProposerSignature[] memory proposerSignatures = new NounsDAOStorageV3.ProposerSignature[](1); - proposerSignatures[0] = NounsDAOStorageV3.ProposerSignature( + NounsDAOTypes.ProposerSignature[] memory proposerSignatures = new NounsDAOTypes.ProposerSignature[](1); + proposerSignatures[0] = NounsDAOTypes.ProposerSignature( signProposal(proposerWithVote, signerWithVote1PK, txs, 'description', expirationTimestamp, address(dao)), signerWithVote1, expirationTimestamp @@ -389,25 +388,25 @@ contract ProposeBySigsTest is NounsDAOLogicV3BaseTest { vm.stopPrank(); assertEq(dao.proposalThreshold(), 1); - NounsDAOV3Proposals.ProposalTxs memory txs = makeTxs(makeAddr('target'), 0, '', ''); + NounsDAOProposals.ProposalTxs memory txs = makeTxs(makeAddr('target'), 0, '', ''); uint256 expirationTimestamp = block.timestamp + 1234; - NounsDAOStorageV3.ProposerSignature[] memory proposerSignatures = new NounsDAOStorageV3.ProposerSignature[](1); - proposerSignatures[0] = NounsDAOStorageV3.ProposerSignature( + NounsDAOTypes.ProposerSignature[] memory proposerSignatures = new NounsDAOTypes.ProposerSignature[](1); + proposerSignatures[0] = NounsDAOTypes.ProposerSignature( signProposal(proposerWithVote, proposerWithVotePK, txs, 'description', expirationTimestamp, address(dao)), proposerWithVote, expirationTimestamp ); vm.prank(proposerWithVote); - vm.expectRevert(NounsDAOV3Proposals.ProposerAlreadyHasALiveProposal.selector); + vm.expectRevert(NounsDAOProposals.ProposerAlreadyHasALiveProposal.selector); dao.proposeBySigs(proposerSignatures, txs.targets, txs.values, txs.signatures, txs.calldatas, 'description'); } function test_givenProposerWithNoVotesAndSignerWithEnoughVotes_worksAndEmitsEvents() public { - NounsDAOV3Proposals.ProposalTxs memory txs = makeTxs(makeAddr('target'), 0, '', ''); + NounsDAOProposals.ProposalTxs memory txs = makeTxs(makeAddr('target'), 0, '', ''); uint256 expirationTimestamp = block.timestamp + 1234; - NounsDAOStorageV3.ProposerSignature[] memory proposerSignatures = new NounsDAOStorageV3.ProposerSignature[](1); - proposerSignatures[0] = NounsDAOStorageV3.ProposerSignature( + NounsDAOTypes.ProposerSignature[] memory proposerSignatures = new NounsDAOTypes.ProposerSignature[](1); + proposerSignatures[0] = NounsDAOTypes.ProposerSignature( signProposal(proposerWithNoVotes, signerWithVote1PK, txs, 'description', expirationTimestamp, address(dao)), signerWithVote1, expirationTimestamp @@ -422,10 +421,10 @@ contract ProposeBySigsTest is NounsDAOLogicV3BaseTest { } function test_givenOnesOfSignersHasNoVotes_signerIsFilteredOut() public { - NounsDAOV3Proposals.ProposalTxs memory txs = makeTxs(makeAddr('target'), 0, '', ''); + NounsDAOProposals.ProposalTxs memory txs = makeTxs(makeAddr('target'), 0, '', ''); uint256 expirationTimestamp = block.timestamp + 1234; - NounsDAOStorageV3.ProposerSignature[] memory proposerSignatures = new NounsDAOStorageV3.ProposerSignature[](2); - proposerSignatures[0] = NounsDAOStorageV3.ProposerSignature( + NounsDAOTypes.ProposerSignature[] memory proposerSignatures = new NounsDAOTypes.ProposerSignature[](2); + proposerSignatures[0] = NounsDAOTypes.ProposerSignature( signProposal( proposerWithNoVotes, signerWithNoVotesPK, @@ -437,7 +436,7 @@ contract ProposeBySigsTest is NounsDAOLogicV3BaseTest { signerWithNoVotes, expirationTimestamp ); - proposerSignatures[1] = NounsDAOStorageV3.ProposerSignature( + proposerSignatures[1] = NounsDAOTypes.ProposerSignature( signProposal(proposerWithNoVotes, signerWithVote2PK, txs, 'description', expirationTimestamp, address(dao)), signerWithVote2, expirationTimestamp @@ -457,7 +456,7 @@ contract ProposeBySigsTest is NounsDAOLogicV3BaseTest { 'description' ); - NounsDAOStorageV3.ProposalCondensed memory proposal = dao.proposalsV3(proposalId); + NounsDAOTypes.ProposalCondensedV3 memory proposal = dao.proposalsV3(proposalId); assertEq(proposal.signers, expectedSigners); } @@ -470,15 +469,15 @@ contract ProposeBySigsTest is NounsDAOLogicV3BaseTest { vm.roll(block.number + 1); vm.stopPrank(); - NounsDAOV3Proposals.ProposalTxs memory txs = makeTxs(makeAddr('target'), 0, '', ''); + NounsDAOProposals.ProposalTxs memory txs = makeTxs(makeAddr('target'), 0, '', ''); uint256 expirationTimestamp = block.timestamp + 1234; - NounsDAOStorageV3.ProposerSignature[] memory proposerSignatures = new NounsDAOStorageV3.ProposerSignature[](2); - proposerSignatures[0] = NounsDAOStorageV3.ProposerSignature( + NounsDAOTypes.ProposerSignature[] memory proposerSignatures = new NounsDAOTypes.ProposerSignature[](2); + proposerSignatures[0] = NounsDAOTypes.ProposerSignature( signProposal(proposerWithNoVotes, signerWithVote1PK, txs, 'description', expirationTimestamp, address(dao)), signerWithVote1, expirationTimestamp ); - proposerSignatures[1] = NounsDAOStorageV3.ProposerSignature( + proposerSignatures[1] = NounsDAOTypes.ProposerSignature( signProposal(proposerWithNoVotes, signerWithVote2PK, txs, 'description', expirationTimestamp, address(dao)), signerWithVote2, expirationTimestamp @@ -499,7 +498,7 @@ contract ProposeBySigsTest is NounsDAOLogicV3BaseTest { 'description' ); - NounsDAOStorageV3.ProposalCondensed memory proposal = dao.proposalsV3(proposalId); + NounsDAOTypes.ProposalCondensedV3 memory proposal = dao.proposalsV3(proposalId); assertEq(proposal.signers, expectedSigners); } @@ -512,15 +511,15 @@ contract ProposeBySigsTest is NounsDAOLogicV3BaseTest { vm.roll(block.number + 1); vm.stopPrank(); - NounsDAOV3Proposals.ProposalTxs memory txs = makeTxs(makeAddr('target'), 0, '', ''); + NounsDAOProposals.ProposalTxs memory txs = makeTxs(makeAddr('target'), 0, '', ''); uint256 expirationTimestamp = block.timestamp + 1234; - NounsDAOStorageV3.ProposerSignature[] memory proposerSignatures = new NounsDAOStorageV3.ProposerSignature[](2); - proposerSignatures[0] = NounsDAOStorageV3.ProposerSignature( + NounsDAOTypes.ProposerSignature[] memory proposerSignatures = new NounsDAOTypes.ProposerSignature[](2); + proposerSignatures[0] = NounsDAOTypes.ProposerSignature( signProposal(proposerWithNoVotes, signerWithVote1PK, txs, 'description', expirationTimestamp, address(dao)), signerWithVote1, expirationTimestamp ); - proposerSignatures[1] = NounsDAOStorageV3.ProposerSignature( + proposerSignatures[1] = NounsDAOTypes.ProposerSignature( signProposal( proposerWithNoVotes, signerWithVote1PK, @@ -534,7 +533,7 @@ contract ProposeBySigsTest is NounsDAOLogicV3BaseTest { ); vm.prank(proposerWithNoVotes); - vm.expectRevert(NounsDAOV3Proposals.ProposerAlreadyHasALiveProposal.selector); + vm.expectRevert(NounsDAOProposals.ProposerAlreadyHasALiveProposal.selector); dao.proposeBySigs(proposerSignatures, txs.targets, txs.values, txs.signatures, txs.calldatas, 'description'); } @@ -544,10 +543,10 @@ contract ProposeBySigsTest is NounsDAOLogicV3BaseTest { nounsToken.delegate(address(erc1271)); vm.roll(block.number + 1); - NounsDAOV3Proposals.ProposalTxs memory txs = makeTxs(makeAddr('target'), 0, '', ''); + NounsDAOProposals.ProposalTxs memory txs = makeTxs(makeAddr('target'), 0, '', ''); uint256 expirationTimestamp = block.timestamp + 1234; - NounsDAOStorageV3.ProposerSignature[] memory proposerSignatures = new NounsDAOStorageV3.ProposerSignature[](1); - proposerSignatures[0] = NounsDAOStorageV3.ProposerSignature( + NounsDAOTypes.ProposerSignature[] memory proposerSignatures = new NounsDAOTypes.ProposerSignature[](1); + proposerSignatures[0] = NounsDAOTypes.ProposerSignature( signProposal(proposerWithNoVotes, signerWithVote1PK, txs, 'description', expirationTimestamp, address(dao)), address(erc1271), expirationTimestamp diff --git a/packages/nouns-contracts/test/foundry/NounsDAOLogicV3/UpdateProposal.t.sol b/packages/nouns-contracts/test/foundry/NounsDAOLogic/UpdateProposal.t.sol similarity index 67% rename from packages/nouns-contracts/test/foundry/NounsDAOLogicV3/UpdateProposal.t.sol rename to packages/nouns-contracts/test/foundry/NounsDAOLogic/UpdateProposal.t.sol index 474c5e90be..33175c4e6e 100644 --- a/packages/nouns-contracts/test/foundry/NounsDAOLogicV3/UpdateProposal.t.sol +++ b/packages/nouns-contracts/test/foundry/NounsDAOLogic/UpdateProposal.t.sol @@ -2,19 +2,18 @@ pragma solidity ^0.8.15; import 'forge-std/Test.sol'; -import { NounsDAOLogicV3BaseTest } from './NounsDAOLogicV3BaseTest.sol'; +import { NounsDAOLogicBaseTest } from './NounsDAOLogicBaseTest.sol'; import { DeployUtils } from '../helpers/DeployUtils.sol'; import { SigUtils, ERC1271Stub } from '../helpers/SigUtils.sol'; -import { NounsDAOLogicV3 } from '../../../contracts/governance/NounsDAOLogicV3.sol'; -import { NounsDAOV3Proposals } from '../../../contracts/governance/NounsDAOV3Proposals.sol'; +import { NounsDAOProposals } from '../../../contracts/governance/NounsDAOProposals.sol'; import { NounsDAOProxyV3 } from '../../../contracts/governance/NounsDAOProxyV3.sol'; -import { NounsDAOStorageV3 } from '../../../contracts/governance/NounsDAOInterfaces.sol'; +import { NounsDAOTypes } from '../../../contracts/governance/NounsDAOInterfaces.sol'; import { NounsToken } from '../../../contracts/NounsToken.sol'; import { NounsSeeder } from '../../../contracts/NounsSeeder.sol'; import { IProxyRegistry } from '../../../contracts/external/opensea/IProxyRegistry.sol'; import { NounsDAOExecutor } from '../../../contracts/governance/NounsDAOExecutor.sol'; -abstract contract UpdateProposalBaseTest is NounsDAOLogicV3BaseTest { +abstract contract UpdateProposalBaseTest is NounsDAOLogicBaseTest { address proposer = makeAddr('proposer'); uint256 proposalId; @@ -47,13 +46,13 @@ contract UpdateProposalPermissionsTest is UpdateProposalBaseTest { } function test_givenMsgSenderNotProposer_reverts() public { - vm.expectRevert(abi.encodeWithSelector(NounsDAOV3Proposals.OnlyProposerCanEdit.selector)); + vm.expectRevert(abi.encodeWithSelector(NounsDAOProposals.OnlyProposerCanEdit.selector)); updateProposal(makeAddr('not proposer'), proposalId, makeAddr('target'), 0, '', '', ''); - vm.expectRevert(abi.encodeWithSelector(NounsDAOV3Proposals.OnlyProposerCanEdit.selector)); + vm.expectRevert(abi.encodeWithSelector(NounsDAOProposals.OnlyProposerCanEdit.selector)); updateProposalTransactions(makeAddr('not proposer'), proposalId, makeAddr('target'), 0, '', '', ''); - vm.expectRevert(abi.encodeWithSelector(NounsDAOV3Proposals.OnlyProposerCanEdit.selector)); + vm.expectRevert(abi.encodeWithSelector(NounsDAOProposals.OnlyProposerCanEdit.selector)); vm.prank(makeAddr('not proposer')); dao.updateProposalDescription(proposalId, '', ''); } @@ -77,13 +76,13 @@ contract UpdateProposalPermissionsTest is UpdateProposalBaseTest { expirationTimestamp ); - vm.expectRevert(abi.encodeWithSelector(NounsDAOV3Proposals.ProposerCannotUpdateProposalWithSigners.selector)); + vm.expectRevert(abi.encodeWithSelector(NounsDAOProposals.ProposerCannotUpdateProposalWithSigners.selector)); updateProposal(proposer, propId, makeAddr('target'), 1, '', '', 'description'); - vm.expectRevert(abi.encodeWithSelector(NounsDAOV3Proposals.ProposerCannotUpdateProposalWithSigners.selector)); + vm.expectRevert(abi.encodeWithSelector(NounsDAOProposals.ProposerCannotUpdateProposalWithSigners.selector)); updateProposalTransactions(proposer, propId, makeAddr('target'), 0, '', '', ''); - vm.expectRevert(abi.encodeWithSelector(NounsDAOV3Proposals.ProposerCannotUpdateProposalWithSigners.selector)); + vm.expectRevert(abi.encodeWithSelector(NounsDAOProposals.ProposerCannotUpdateProposalWithSigners.selector)); vm.prank(proposer); dao.updateProposalDescription(propId, '', ''); } @@ -91,27 +90,27 @@ contract UpdateProposalPermissionsTest is UpdateProposalBaseTest { function test_givenStatesPendingActiveSucceededQueuedAndExecuted_reverts() public { // Pending vm.roll(block.number + proposalUpdatablePeriodInBlocks); - assertTrue(dao.state(proposalId) == NounsDAOStorageV3.ProposalState.Pending); - vm.expectRevert(abi.encodeWithSelector(NounsDAOV3Proposals.CanOnlyEditUpdatableProposals.selector)); + assertTrue(dao.state(proposalId) == NounsDAOTypes.ProposalState.Pending); + vm.expectRevert(abi.encodeWithSelector(NounsDAOProposals.CanOnlyEditUpdatableProposals.selector)); updateProposal(proposer, proposalId, makeAddr('target'), 0, '', '', ''); - vm.expectRevert(abi.encodeWithSelector(NounsDAOV3Proposals.CanOnlyEditUpdatableProposals.selector)); + vm.expectRevert(abi.encodeWithSelector(NounsDAOProposals.CanOnlyEditUpdatableProposals.selector)); updateProposalTransactions(proposer, proposalId, makeAddr('target'), 0, '', '', ''); - vm.expectRevert(abi.encodeWithSelector(NounsDAOV3Proposals.CanOnlyEditUpdatableProposals.selector)); + vm.expectRevert(abi.encodeWithSelector(NounsDAOProposals.CanOnlyEditUpdatableProposals.selector)); vm.prank(proposer); dao.updateProposalDescription(proposalId, '', ''); // Active vm.roll(block.number + VOTING_DELAY); - assertTrue(dao.state(proposalId) == NounsDAOStorageV3.ProposalState.Active); - vm.expectRevert(abi.encodeWithSelector(NounsDAOV3Proposals.CanOnlyEditUpdatableProposals.selector)); + assertTrue(dao.state(proposalId) == NounsDAOTypes.ProposalState.Active); + vm.expectRevert(abi.encodeWithSelector(NounsDAOProposals.CanOnlyEditUpdatableProposals.selector)); updateProposal(proposer, proposalId, makeAddr('target'), 0, '', '', ''); - vm.expectRevert(abi.encodeWithSelector(NounsDAOV3Proposals.CanOnlyEditUpdatableProposals.selector)); + vm.expectRevert(abi.encodeWithSelector(NounsDAOProposals.CanOnlyEditUpdatableProposals.selector)); updateProposalTransactions(proposer, proposalId, makeAddr('target'), 0, '', '', ''); - vm.expectRevert(abi.encodeWithSelector(NounsDAOV3Proposals.CanOnlyEditUpdatableProposals.selector)); + vm.expectRevert(abi.encodeWithSelector(NounsDAOProposals.CanOnlyEditUpdatableProposals.selector)); vm.prank(proposer); dao.updateProposalDescription(proposalId, '', ''); @@ -119,41 +118,41 @@ contract UpdateProposalPermissionsTest is UpdateProposalBaseTest { vm.prank(proposer); dao.castVote(proposalId, 1); vm.roll(block.number + VOTING_PERIOD); - assertTrue(dao.state(proposalId) == NounsDAOStorageV3.ProposalState.Succeeded); - vm.expectRevert(abi.encodeWithSelector(NounsDAOV3Proposals.CanOnlyEditUpdatableProposals.selector)); + assertTrue(dao.state(proposalId) == NounsDAOTypes.ProposalState.Succeeded); + vm.expectRevert(abi.encodeWithSelector(NounsDAOProposals.CanOnlyEditUpdatableProposals.selector)); updateProposal(proposer, proposalId, makeAddr('target'), 0, '', '', ''); - vm.expectRevert(abi.encodeWithSelector(NounsDAOV3Proposals.CanOnlyEditUpdatableProposals.selector)); + vm.expectRevert(abi.encodeWithSelector(NounsDAOProposals.CanOnlyEditUpdatableProposals.selector)); updateProposalTransactions(proposer, proposalId, makeAddr('target'), 0, '', '', ''); - vm.expectRevert(abi.encodeWithSelector(NounsDAOV3Proposals.CanOnlyEditUpdatableProposals.selector)); + vm.expectRevert(abi.encodeWithSelector(NounsDAOProposals.CanOnlyEditUpdatableProposals.selector)); vm.prank(proposer); dao.updateProposalDescription(proposalId, '', ''); // Queued dao.queue(proposalId); - assertTrue(dao.state(proposalId) == NounsDAOStorageV3.ProposalState.Queued); - vm.expectRevert(abi.encodeWithSelector(NounsDAOV3Proposals.CanOnlyEditUpdatableProposals.selector)); + assertTrue(dao.state(proposalId) == NounsDAOTypes.ProposalState.Queued); + vm.expectRevert(abi.encodeWithSelector(NounsDAOProposals.CanOnlyEditUpdatableProposals.selector)); updateProposal(proposer, proposalId, makeAddr('target'), 0, '', '', ''); - vm.expectRevert(abi.encodeWithSelector(NounsDAOV3Proposals.CanOnlyEditUpdatableProposals.selector)); + vm.expectRevert(abi.encodeWithSelector(NounsDAOProposals.CanOnlyEditUpdatableProposals.selector)); updateProposalTransactions(proposer, proposalId, makeAddr('target'), 0, '', '', ''); - vm.expectRevert(abi.encodeWithSelector(NounsDAOV3Proposals.CanOnlyEditUpdatableProposals.selector)); + vm.expectRevert(abi.encodeWithSelector(NounsDAOProposals.CanOnlyEditUpdatableProposals.selector)); vm.prank(proposer); dao.updateProposalDescription(proposalId, '', ''); // Executed vm.warp(block.timestamp + TIMELOCK_DELAY); dao.execute(proposalId); - assertTrue(dao.state(proposalId) == NounsDAOStorageV3.ProposalState.Executed); - vm.expectRevert(abi.encodeWithSelector(NounsDAOV3Proposals.CanOnlyEditUpdatableProposals.selector)); + assertTrue(dao.state(proposalId) == NounsDAOTypes.ProposalState.Executed); + vm.expectRevert(abi.encodeWithSelector(NounsDAOProposals.CanOnlyEditUpdatableProposals.selector)); updateProposal(proposer, proposalId, makeAddr('target'), 0, '', '', ''); - vm.expectRevert(abi.encodeWithSelector(NounsDAOV3Proposals.CanOnlyEditUpdatableProposals.selector)); + vm.expectRevert(abi.encodeWithSelector(NounsDAOProposals.CanOnlyEditUpdatableProposals.selector)); updateProposalTransactions(proposer, proposalId, makeAddr('target'), 0, '', '', ''); - vm.expectRevert(abi.encodeWithSelector(NounsDAOV3Proposals.CanOnlyEditUpdatableProposals.selector)); + vm.expectRevert(abi.encodeWithSelector(NounsDAOProposals.CanOnlyEditUpdatableProposals.selector)); vm.prank(proposer); dao.updateProposalDescription(proposalId, '', ''); } @@ -161,15 +160,15 @@ contract UpdateProposalPermissionsTest is UpdateProposalBaseTest { function test_givenStateCanceled_reverts() public { vm.prank(proposer); dao.cancel(proposalId); - assertTrue(dao.state(proposalId) == NounsDAOStorageV3.ProposalState.Canceled); + assertTrue(dao.state(proposalId) == NounsDAOTypes.ProposalState.Canceled); - vm.expectRevert(abi.encodeWithSelector(NounsDAOV3Proposals.CanOnlyEditUpdatableProposals.selector)); + vm.expectRevert(abi.encodeWithSelector(NounsDAOProposals.CanOnlyEditUpdatableProposals.selector)); updateProposal(proposer, proposalId, makeAddr('target'), 0, '', '', ''); - vm.expectRevert(abi.encodeWithSelector(NounsDAOV3Proposals.CanOnlyEditUpdatableProposals.selector)); + vm.expectRevert(abi.encodeWithSelector(NounsDAOProposals.CanOnlyEditUpdatableProposals.selector)); updateProposalTransactions(proposer, proposalId, makeAddr('target'), 0, '', '', ''); - vm.expectRevert(abi.encodeWithSelector(NounsDAOV3Proposals.CanOnlyEditUpdatableProposals.selector)); + vm.expectRevert(abi.encodeWithSelector(NounsDAOProposals.CanOnlyEditUpdatableProposals.selector)); vm.prank(proposer); dao.updateProposalDescription(proposalId, '', ''); } @@ -179,15 +178,15 @@ contract UpdateProposalPermissionsTest is UpdateProposalBaseTest { vm.prank(proposer); dao.castVote(proposalId, 0); vm.roll(block.number + VOTING_PERIOD); - assertTrue(dao.state(proposalId) == NounsDAOStorageV3.ProposalState.Defeated); + assertTrue(dao.state(proposalId) == NounsDAOTypes.ProposalState.Defeated); - vm.expectRevert(abi.encodeWithSelector(NounsDAOV3Proposals.CanOnlyEditUpdatableProposals.selector)); + vm.expectRevert(abi.encodeWithSelector(NounsDAOProposals.CanOnlyEditUpdatableProposals.selector)); updateProposal(proposer, proposalId, makeAddr('target'), 0, '', '', ''); - vm.expectRevert(abi.encodeWithSelector(NounsDAOV3Proposals.CanOnlyEditUpdatableProposals.selector)); + vm.expectRevert(abi.encodeWithSelector(NounsDAOProposals.CanOnlyEditUpdatableProposals.selector)); updateProposalTransactions(proposer, proposalId, makeAddr('target'), 0, '', '', ''); - vm.expectRevert(abi.encodeWithSelector(NounsDAOV3Proposals.CanOnlyEditUpdatableProposals.selector)); + vm.expectRevert(abi.encodeWithSelector(NounsDAOProposals.CanOnlyEditUpdatableProposals.selector)); vm.prank(proposer); dao.updateProposalDescription(proposalId, '', ''); } @@ -199,15 +198,15 @@ contract UpdateProposalPermissionsTest is UpdateProposalBaseTest { vm.roll(block.number + VOTING_PERIOD); dao.queue(proposalId); vm.warp(block.timestamp + TIMELOCK_DELAY + timelock.GRACE_PERIOD()); - assertTrue(dao.state(proposalId) == NounsDAOStorageV3.ProposalState.Expired); + assertTrue(dao.state(proposalId) == NounsDAOTypes.ProposalState.Expired); - vm.expectRevert(abi.encodeWithSelector(NounsDAOV3Proposals.CanOnlyEditUpdatableProposals.selector)); + vm.expectRevert(abi.encodeWithSelector(NounsDAOProposals.CanOnlyEditUpdatableProposals.selector)); updateProposal(proposer, proposalId, makeAddr('target'), 0, '', '', ''); - vm.expectRevert(abi.encodeWithSelector(NounsDAOV3Proposals.CanOnlyEditUpdatableProposals.selector)); + vm.expectRevert(abi.encodeWithSelector(NounsDAOProposals.CanOnlyEditUpdatableProposals.selector)); updateProposalTransactions(proposer, proposalId, makeAddr('target'), 0, '', '', ''); - vm.expectRevert(abi.encodeWithSelector(NounsDAOV3Proposals.CanOnlyEditUpdatableProposals.selector)); + vm.expectRevert(abi.encodeWithSelector(NounsDAOProposals.CanOnlyEditUpdatableProposals.selector)); vm.prank(proposer); dao.updateProposalDescription(proposalId, '', ''); } @@ -215,15 +214,15 @@ contract UpdateProposalPermissionsTest is UpdateProposalBaseTest { function test_givenStateVetoed_reverts() public { vm.prank(vetoer); dao.veto(proposalId); - assertTrue(dao.state(proposalId) == NounsDAOStorageV3.ProposalState.Vetoed); + assertTrue(dao.state(proposalId) == NounsDAOTypes.ProposalState.Vetoed); - vm.expectRevert(abi.encodeWithSelector(NounsDAOV3Proposals.CanOnlyEditUpdatableProposals.selector)); + vm.expectRevert(abi.encodeWithSelector(NounsDAOProposals.CanOnlyEditUpdatableProposals.selector)); updateProposal(proposer, proposalId, makeAddr('target'), 0, '', '', ''); - vm.expectRevert(abi.encodeWithSelector(NounsDAOV3Proposals.CanOnlyEditUpdatableProposals.selector)); + vm.expectRevert(abi.encodeWithSelector(NounsDAOProposals.CanOnlyEditUpdatableProposals.selector)); updateProposalTransactions(proposer, proposalId, makeAddr('target'), 0, '', '', ''); - vm.expectRevert(abi.encodeWithSelector(NounsDAOV3Proposals.CanOnlyEditUpdatableProposals.selector)); + vm.expectRevert(abi.encodeWithSelector(NounsDAOProposals.CanOnlyEditUpdatableProposals.selector)); vm.prank(proposer); dao.updateProposalDescription(proposalId, '', ''); } @@ -235,15 +234,15 @@ contract UpdateProposalPermissionsTest is UpdateProposalBaseTest { vm.prank(proposer); dao.castVote(proposalId, 1); vm.roll(block.number + lastMinuteWindowInBlocks); - assertTrue(dao.state(proposalId) == NounsDAOStorageV3.ProposalState.ObjectionPeriod); + assertTrue(dao.state(proposalId) == NounsDAOTypes.ProposalState.ObjectionPeriod); - vm.expectRevert(abi.encodeWithSelector(NounsDAOV3Proposals.CanOnlyEditUpdatableProposals.selector)); + vm.expectRevert(abi.encodeWithSelector(NounsDAOProposals.CanOnlyEditUpdatableProposals.selector)); updateProposal(proposer, proposalId, makeAddr('target'), 0, '', '', ''); - vm.expectRevert(abi.encodeWithSelector(NounsDAOV3Proposals.CanOnlyEditUpdatableProposals.selector)); + vm.expectRevert(abi.encodeWithSelector(NounsDAOProposals.CanOnlyEditUpdatableProposals.selector)); updateProposalTransactions(proposer, proposalId, makeAddr('target'), 0, '', '', ''); - vm.expectRevert(abi.encodeWithSelector(NounsDAOV3Proposals.CanOnlyEditUpdatableProposals.selector)); + vm.expectRevert(abi.encodeWithSelector(NounsDAOProposals.CanOnlyEditUpdatableProposals.selector)); vm.prank(proposer); dao.updateProposalDescription(proposalId, '', ''); } @@ -260,11 +259,11 @@ contract UpdateProposalTransactionsTest is UpdateProposalBaseTest { string[] memory signatures = new string[](0); bytes[] memory calldatas = new bytes[](0); - vm.expectRevert(abi.encodeWithSelector(NounsDAOV3Proposals.MustProvideActions.selector)); + vm.expectRevert(abi.encodeWithSelector(NounsDAOProposals.MustProvideActions.selector)); vm.prank(proposer); dao.updateProposal(proposalId, targets, values, signatures, calldatas, '', ''); - vm.expectRevert(abi.encodeWithSelector(NounsDAOV3Proposals.MustProvideActions.selector)); + vm.expectRevert(abi.encodeWithSelector(NounsDAOProposals.MustProvideActions.selector)); vm.prank(proposer); dao.updateProposalTransactions(proposalId, targets, values, signatures, calldatas, ''); } @@ -281,11 +280,11 @@ contract UpdateProposalTransactionsTest is UpdateProposalBaseTest { calldatas[i] = ''; } - vm.expectRevert(abi.encodeWithSelector(NounsDAOV3Proposals.TooManyActions.selector)); + vm.expectRevert(abi.encodeWithSelector(NounsDAOProposals.TooManyActions.selector)); vm.prank(proposer); dao.updateProposal(proposalId, targets, values, signatures, calldatas, '', ''); - vm.expectRevert(abi.encodeWithSelector(NounsDAOV3Proposals.TooManyActions.selector)); + vm.expectRevert(abi.encodeWithSelector(NounsDAOProposals.TooManyActions.selector)); vm.prank(proposer); dao.updateProposalTransactions(proposalId, targets, values, signatures, calldatas, ''); } @@ -297,17 +296,17 @@ contract UpdateProposalTransactionsTest is UpdateProposalBaseTest { string[] memory signatures = new string[](0); bytes[] memory calldatas = new bytes[](0); - vm.expectRevert(abi.encodeWithSelector(NounsDAOV3Proposals.ProposalInfoArityMismatch.selector)); + vm.expectRevert(abi.encodeWithSelector(NounsDAOProposals.ProposalInfoArityMismatch.selector)); vm.prank(proposer); dao.updateProposal(proposalId, targets, values, signatures, calldatas, '', ''); - vm.expectRevert(abi.encodeWithSelector(NounsDAOV3Proposals.ProposalInfoArityMismatch.selector)); + vm.expectRevert(abi.encodeWithSelector(NounsDAOProposals.ProposalInfoArityMismatch.selector)); vm.prank(proposer); dao.updateProposalTransactions(proposalId, targets, values, signatures, calldatas, ''); } function test_givenStateUpdatable_updateProposal_updatesTxsAndEmitsEvent() public { - assertTrue(dao.state(proposalId) == NounsDAOStorageV3.ProposalState.Updatable); + assertTrue(dao.state(proposalId) == NounsDAOTypes.ProposalState.Updatable); ( address[] memory targetsBefore, uint256[] memory valuesBefore, @@ -318,7 +317,7 @@ contract UpdateProposalTransactionsTest is UpdateProposalBaseTest { assertEq(valuesBefore[0], 0); assertEq(signaturesBefore[0], ''); assertEq(calldatasBefore[0], ''); - NounsDAOV3Proposals.ProposalTxs memory txsAfter = makeTxs( + NounsDAOProposals.ProposalTxs memory txsAfter = makeTxs( makeAddr('targetAfter'), 1, 'signatureAfter', @@ -360,7 +359,7 @@ contract UpdateProposalTransactionsTest is UpdateProposalBaseTest { } function test_givenStateUpdatable_updateProposalTransactions_updatesTxsAndEmitsEvent() public { - assertTrue(dao.state(proposalId) == NounsDAOStorageV3.ProposalState.Updatable); + assertTrue(dao.state(proposalId) == NounsDAOTypes.ProposalState.Updatable); ( address[] memory targetsBefore, uint256[] memory valuesBefore, @@ -371,7 +370,7 @@ contract UpdateProposalTransactionsTest is UpdateProposalBaseTest { assertEq(valuesBefore[0], 0); assertEq(signaturesBefore[0], ''); assertEq(calldatasBefore[0], ''); - NounsDAOV3Proposals.ProposalTxs memory txsAfter = makeTxs( + NounsDAOProposals.ProposalTxs memory txsAfter = makeTxs( makeAddr('targetAfter'), 1, 'signatureAfter', @@ -413,7 +412,7 @@ contract UpdateProposalTransactionsTest is UpdateProposalBaseTest { contract UpdateProposalDescriptionTest is UpdateProposalBaseTest { function test_givenStateUpdatable_updatesDescriptionAndEmitsEvent() public { - assertTrue(dao.state(proposalId) == NounsDAOStorageV3.ProposalState.Updatable); + assertTrue(dao.state(proposalId) == NounsDAOTypes.ProposalState.Updatable); vm.expectEmit(true, true, true, true); emit ProposalDescriptionUpdated(proposalId, proposer, 'new description', 'update message'); diff --git a/packages/nouns-contracts/test/foundry/NounsDAOLogicV3/UpdateProposalBySigs.t.sol b/packages/nouns-contracts/test/foundry/NounsDAOLogic/UpdateProposalBySigs.t.sol similarity index 71% rename from packages/nouns-contracts/test/foundry/NounsDAOLogicV3/UpdateProposalBySigs.t.sol rename to packages/nouns-contracts/test/foundry/NounsDAOLogic/UpdateProposalBySigs.t.sol index 4338ce5b63..bb5fcb9279 100644 --- a/packages/nouns-contracts/test/foundry/NounsDAOLogicV3/UpdateProposalBySigs.t.sol +++ b/packages/nouns-contracts/test/foundry/NounsDAOLogic/UpdateProposalBySigs.t.sol @@ -3,19 +3,18 @@ pragma solidity ^0.8.15; import 'forge-std/Test.sol'; import { Strings } from '@openzeppelin/contracts/utils/Strings.sol'; -import { NounsDAOLogicV3BaseTest } from './NounsDAOLogicV3BaseTest.sol'; +import { NounsDAOLogicBaseTest } from './NounsDAOLogicBaseTest.sol'; import { DeployUtils } from '../helpers/DeployUtils.sol'; import { SigUtils, ERC1271Stub } from '../helpers/SigUtils.sol'; -import { NounsDAOLogicV3 } from '../../../contracts/governance/NounsDAOLogicV3.sol'; -import { NounsDAOV3Proposals } from '../../../contracts/governance/NounsDAOV3Proposals.sol'; +import { NounsDAOProposals } from '../../../contracts/governance/NounsDAOProposals.sol'; import { NounsDAOProxyV3 } from '../../../contracts/governance/NounsDAOProxyV3.sol'; -import { NounsDAOStorageV3 } from '../../../contracts/governance/NounsDAOInterfaces.sol'; +import { NounsDAOTypes } from '../../../contracts/governance/NounsDAOInterfaces.sol'; import { NounsToken } from '../../../contracts/NounsToken.sol'; import { NounsSeeder } from '../../../contracts/NounsSeeder.sol'; import { IProxyRegistry } from '../../../contracts/external/opensea/IProxyRegistry.sol'; import { NounsDAOExecutor } from '../../../contracts/governance/NounsDAOExecutor.sol'; -contract UpdateProposalBySigsTest is NounsDAOLogicV3BaseTest { +contract UpdateProposalBySigsTest is NounsDAOLogicBaseTest { address proposer = makeAddr('proposerWithVote'); address[] _signers; uint256[] _signerPKs; @@ -62,7 +61,7 @@ contract UpdateProposalBySigsTest is NounsDAOLogicV3BaseTest { uint256[] memory signerPKs = new uint256[](0); uint256[] memory expirationTimestamps = new uint256[](0); - vm.expectRevert(abi.encodeWithSelector(NounsDAOV3Proposals.MustProvideSignatures.selector)); + vm.expectRevert(abi.encodeWithSelector(NounsDAOProposals.MustProvideSignatures.selector)); updateProposalBySigs( proposalId, proposer, @@ -80,8 +79,8 @@ contract UpdateProposalBySigsTest is NounsDAOLogicV3BaseTest { uint256[] memory signerPKs, uint256[] memory expirationTimestamps ) = signersPKsExpirations(); - NounsDAOV3Proposals.ProposalTxs memory txs = makeTxs(makeAddr('new target'), 0, '', ''); - NounsDAOStorageV3.ProposerSignature[] memory sigs = makeUpdateProposalSigs( + NounsDAOProposals.ProposalTxs memory txs = makeTxs(makeAddr('new target'), 0, '', ''); + NounsDAOTypes.ProposerSignature[] memory sigs = makeUpdateProposalSigs( signers, signerPKs, expirationTimestamps, @@ -90,7 +89,7 @@ contract UpdateProposalBySigsTest is NounsDAOLogicV3BaseTest { ); vm.prank(makeAddr('not proposer')); - vm.expectRevert(abi.encodeWithSelector(NounsDAOV3Proposals.OnlyProposerCanEdit.selector)); + vm.expectRevert(abi.encodeWithSelector(NounsDAOProposals.OnlyProposerCanEdit.selector)); dao.updateProposalBySigs(proposalId, sigs, txs.targets, txs.values, txs.signatures, txs.calldatas, '', ''); } @@ -100,8 +99,8 @@ contract UpdateProposalBySigsTest is NounsDAOLogicV3BaseTest { uint256[] memory signerPKs, uint256[] memory expirationTimestamps ) = fewerSignersPKsExpirations(); - NounsDAOV3Proposals.ProposalTxs memory txs = makeTxs(makeAddr('new target'), 0, '', ''); - NounsDAOStorageV3.ProposerSignature[] memory sigs = makeUpdateProposalSigs( + NounsDAOProposals.ProposalTxs memory txs = makeTxs(makeAddr('new target'), 0, '', ''); + NounsDAOTypes.ProposerSignature[] memory sigs = makeUpdateProposalSigs( signers, signerPKs, expirationTimestamps, @@ -110,7 +109,7 @@ contract UpdateProposalBySigsTest is NounsDAOLogicV3BaseTest { ); vm.prank(proposer); - vm.expectRevert(abi.encodeWithSelector(NounsDAOV3Proposals.SignerCountMismtach.selector)); + vm.expectRevert(abi.encodeWithSelector(NounsDAOProposals.SignerCountMismtach.selector)); dao.updateProposalBySigs(proposalId, sigs, txs.targets, txs.values, txs.signatures, txs.calldatas, '', ''); } @@ -120,8 +119,8 @@ contract UpdateProposalBySigsTest is NounsDAOLogicV3BaseTest { uint256[] memory signerPKs, uint256[] memory expirationTimestamps ) = moreSignersPKsExpirations(); - NounsDAOV3Proposals.ProposalTxs memory txs = makeTxs(makeAddr('new target'), 0, '', ''); - NounsDAOStorageV3.ProposerSignature[] memory sigs = makeUpdateProposalSigs( + NounsDAOProposals.ProposalTxs memory txs = makeTxs(makeAddr('new target'), 0, '', ''); + NounsDAOTypes.ProposerSignature[] memory sigs = makeUpdateProposalSigs( signers, signerPKs, expirationTimestamps, @@ -130,7 +129,7 @@ contract UpdateProposalBySigsTest is NounsDAOLogicV3BaseTest { ); vm.prank(proposer); - vm.expectRevert(abi.encodeWithSelector(NounsDAOV3Proposals.SignerCountMismtach.selector)); + vm.expectRevert(abi.encodeWithSelector(NounsDAOProposals.SignerCountMismtach.selector)); dao.updateProposalBySigs(proposalId, sigs, txs.targets, txs.values, txs.signatures, txs.calldatas, '', ''); } @@ -145,8 +144,8 @@ contract UpdateProposalBySigsTest is NounsDAOLogicV3BaseTest { signers[1] = _signers[_signers.length - 1]; signerPKs[1] = _signerPKs[_signers.length - 1]; - NounsDAOV3Proposals.ProposalTxs memory txs = makeTxs(makeAddr('new target'), 0, '', ''); - NounsDAOStorageV3.ProposerSignature[] memory sigs = makeUpdateProposalSigs( + NounsDAOProposals.ProposalTxs memory txs = makeTxs(makeAddr('new target'), 0, '', ''); + NounsDAOTypes.ProposerSignature[] memory sigs = makeUpdateProposalSigs( signers, signerPKs, expirationTimestamps, @@ -155,7 +154,7 @@ contract UpdateProposalBySigsTest is NounsDAOLogicV3BaseTest { ); vm.prank(proposer); - vm.expectRevert(abi.encodeWithSelector(NounsDAOV3Proposals.OnlyProposerCanEdit.selector)); + vm.expectRevert(abi.encodeWithSelector(NounsDAOProposals.OnlyProposerCanEdit.selector)); dao.updateProposalBySigs(proposalId, sigs, txs.targets, txs.values, txs.signatures, txs.calldatas, '', ''); } @@ -166,8 +165,8 @@ contract UpdateProposalBySigsTest is NounsDAOLogicV3BaseTest { uint256[] memory expirationTimestamps ) = signersPKsExpirations(); - NounsDAOV3Proposals.ProposalTxs memory txs = makeTxs(makeAddr('new target'), 0, '', ''); - NounsDAOStorageV3.ProposerSignature[] memory sigs = makeUpdateProposalSigs( + NounsDAOProposals.ProposalTxs memory txs = makeTxs(makeAddr('new target'), 0, '', ''); + NounsDAOTypes.ProposerSignature[] memory sigs = makeUpdateProposalSigs( signers, signerPKs, expirationTimestamps, @@ -179,7 +178,7 @@ contract UpdateProposalBySigsTest is NounsDAOLogicV3BaseTest { dao.cancelSig(sigs[1].sig); vm.prank(proposer); - vm.expectRevert(abi.encodeWithSelector(NounsDAOV3Proposals.SignatureIsCancelled.selector)); + vm.expectRevert(abi.encodeWithSelector(NounsDAOProposals.SignatureIsCancelled.selector)); dao.updateProposalBySigs(proposalId, sigs, txs.targets, txs.values, txs.signatures, txs.calldatas, '', ''); } @@ -192,8 +191,8 @@ contract UpdateProposalBySigsTest is NounsDAOLogicV3BaseTest { expirationTimestamps[1] = block.timestamp - 1; - NounsDAOV3Proposals.ProposalTxs memory txs = makeTxs(makeAddr('new target'), 0, '', ''); - NounsDAOStorageV3.ProposerSignature[] memory sigs = makeUpdateProposalSigs( + NounsDAOProposals.ProposalTxs memory txs = makeTxs(makeAddr('new target'), 0, '', ''); + NounsDAOTypes.ProposerSignature[] memory sigs = makeUpdateProposalSigs( signers, signerPKs, expirationTimestamps, @@ -202,7 +201,7 @@ contract UpdateProposalBySigsTest is NounsDAOLogicV3BaseTest { ); vm.prank(proposer); - vm.expectRevert(abi.encodeWithSelector(NounsDAOV3Proposals.SignatureExpired.selector)); + vm.expectRevert(abi.encodeWithSelector(NounsDAOProposals.SignatureExpired.selector)); dao.updateProposalBySigs(proposalId, sigs, txs.targets, txs.values, txs.signatures, txs.calldatas, '', ''); } @@ -213,8 +212,8 @@ contract UpdateProposalBySigsTest is NounsDAOLogicV3BaseTest { uint256[] memory expirationTimestamps ) = signersPKsExpirations(); - NounsDAOV3Proposals.ProposalTxs memory txs = makeTxs(makeAddr('new target'), 0, '', ''); - NounsDAOStorageV3.ProposerSignature[] memory sigs = makeUpdateProposalSigs( + NounsDAOProposals.ProposalTxs memory txs = makeTxs(makeAddr('new target'), 0, '', ''); + NounsDAOTypes.ProposerSignature[] memory sigs = makeUpdateProposalSigs( signers, signerPKs, expirationTimestamps, @@ -223,7 +222,7 @@ contract UpdateProposalBySigsTest is NounsDAOLogicV3BaseTest { ); vm.prank(proposer); - vm.expectRevert(abi.encodeWithSelector(NounsDAOV3Proposals.InvalidSignature.selector)); + vm.expectRevert(abi.encodeWithSelector(NounsDAOProposals.InvalidSignature.selector)); dao.updateProposalBySigs(proposalId, sigs, txs.targets, txs.values, txs.signatures, txs.calldatas, '', ''); } @@ -234,14 +233,14 @@ contract UpdateProposalBySigsTest is NounsDAOLogicV3BaseTest { uint256[] memory expirationTimestamps ) = signersPKsExpirations(); - NounsDAOV3Proposals.ProposalTxs memory txs = makeTxs(makeAddr('new target'), 0, '', ''); + NounsDAOProposals.ProposalTxs memory txs = makeTxs(makeAddr('new target'), 0, '', ''); address[] memory updateTargets = txs.targets; // sign on differet new target address[] memory differentTargets = new address[](1); differentTargets[0] = makeAddr('different new target'); txs.targets = differentTargets; - NounsDAOStorageV3.ProposerSignature[] memory sigs = makeUpdateProposalSigs( + NounsDAOTypes.ProposerSignature[] memory sigs = makeUpdateProposalSigs( signers, signerPKs, expirationTimestamps, @@ -252,7 +251,7 @@ contract UpdateProposalBySigsTest is NounsDAOLogicV3BaseTest { // set it back to the original new target txs.targets = updateTargets; vm.prank(proposer); - vm.expectRevert(abi.encodeWithSelector(NounsDAOV3Proposals.InvalidSignature.selector)); + vm.expectRevert(abi.encodeWithSelector(NounsDAOProposals.InvalidSignature.selector)); dao.updateProposalBySigs(proposalId, sigs, txs.targets, txs.values, txs.signatures, txs.calldatas, '', ''); } @@ -263,14 +262,14 @@ contract UpdateProposalBySigsTest is NounsDAOLogicV3BaseTest { uint256[] memory expirationTimestamps ) = signersPKsExpirations(); - NounsDAOV3Proposals.ProposalTxs memory txs = makeTxs(makeAddr('new target'), 0, '', ''); + NounsDAOProposals.ProposalTxs memory txs = makeTxs(makeAddr('new target'), 0, '', ''); uint256[] memory updateValues = txs.values; // sign on differet values uint256[] memory differentValues = new uint256[](1); differentValues[0] = updateValues[0] + 1234; txs.values = differentValues; - NounsDAOStorageV3.ProposerSignature[] memory sigs = makeUpdateProposalSigs( + NounsDAOTypes.ProposerSignature[] memory sigs = makeUpdateProposalSigs( signers, signerPKs, expirationTimestamps, @@ -281,7 +280,7 @@ contract UpdateProposalBySigsTest is NounsDAOLogicV3BaseTest { // set it back to the original update values txs.values = updateValues; vm.prank(proposer); - vm.expectRevert(abi.encodeWithSelector(NounsDAOV3Proposals.InvalidSignature.selector)); + vm.expectRevert(abi.encodeWithSelector(NounsDAOProposals.InvalidSignature.selector)); dao.updateProposalBySigs(proposalId, sigs, txs.targets, txs.values, txs.signatures, txs.calldatas, '', ''); } @@ -292,14 +291,14 @@ contract UpdateProposalBySigsTest is NounsDAOLogicV3BaseTest { uint256[] memory expirationTimestamps ) = signersPKsExpirations(); - NounsDAOV3Proposals.ProposalTxs memory txs = makeTxs(makeAddr('new target'), 0, '', ''); + NounsDAOProposals.ProposalTxs memory txs = makeTxs(makeAddr('new target'), 0, '', ''); string[] memory updateSignatures = txs.signatures; // sign on differet signatures string[] memory differentSignatures = new string[](1); differentSignatures[0] = 'different signature'; txs.signatures = differentSignatures; - NounsDAOStorageV3.ProposerSignature[] memory sigs = makeUpdateProposalSigs( + NounsDAOTypes.ProposerSignature[] memory sigs = makeUpdateProposalSigs( signers, signerPKs, expirationTimestamps, @@ -310,7 +309,7 @@ contract UpdateProposalBySigsTest is NounsDAOLogicV3BaseTest { // set it back to the original update signatures txs.signatures = updateSignatures; vm.prank(proposer); - vm.expectRevert(abi.encodeWithSelector(NounsDAOV3Proposals.InvalidSignature.selector)); + vm.expectRevert(abi.encodeWithSelector(NounsDAOProposals.InvalidSignature.selector)); dao.updateProposalBySigs(proposalId, sigs, txs.targets, txs.values, txs.signatures, txs.calldatas, '', ''); } @@ -321,14 +320,14 @@ contract UpdateProposalBySigsTest is NounsDAOLogicV3BaseTest { uint256[] memory expirationTimestamps ) = signersPKsExpirations(); - NounsDAOV3Proposals.ProposalTxs memory txs = makeTxs(makeAddr('new target'), 0, '', ''); + NounsDAOProposals.ProposalTxs memory txs = makeTxs(makeAddr('new target'), 0, '', ''); bytes[] memory updateCalldatas = txs.calldatas; // sign on differet calldatas bytes[] memory differentCalldatas = new bytes[](1); differentCalldatas[0] = 'different calldatas'; txs.calldatas = differentCalldatas; - NounsDAOStorageV3.ProposerSignature[] memory sigs = makeUpdateProposalSigs( + NounsDAOTypes.ProposerSignature[] memory sigs = makeUpdateProposalSigs( signers, signerPKs, expirationTimestamps, @@ -339,7 +338,7 @@ contract UpdateProposalBySigsTest is NounsDAOLogicV3BaseTest { // set it back to the original update calldatas txs.calldatas = updateCalldatas; vm.prank(proposer); - vm.expectRevert(abi.encodeWithSelector(NounsDAOV3Proposals.InvalidSignature.selector)); + vm.expectRevert(abi.encodeWithSelector(NounsDAOProposals.InvalidSignature.selector)); dao.updateProposalBySigs(proposalId, sigs, txs.targets, txs.values, txs.signatures, txs.calldatas, '', ''); } @@ -350,8 +349,8 @@ contract UpdateProposalBySigsTest is NounsDAOLogicV3BaseTest { uint256[] memory expirationTimestamps ) = signersPKsExpirations(); - NounsDAOV3Proposals.ProposalTxs memory txs = makeTxs(makeAddr('new target'), 0, '', ''); - NounsDAOStorageV3.ProposerSignature[] memory sigs = makeUpdateProposalSigs( + NounsDAOProposals.ProposalTxs memory txs = makeTxs(makeAddr('new target'), 0, '', ''); + NounsDAOTypes.ProposerSignature[] memory sigs = makeUpdateProposalSigs( signers, signerPKs, expirationTimestamps, @@ -362,7 +361,7 @@ contract UpdateProposalBySigsTest is NounsDAOLogicV3BaseTest { sigs[1].expirationTimestamp = sigs[1].expirationTimestamp + 1234; vm.prank(proposer); - vm.expectRevert(abi.encodeWithSelector(NounsDAOV3Proposals.InvalidSignature.selector)); + vm.expectRevert(abi.encodeWithSelector(NounsDAOProposals.InvalidSignature.selector)); dao.updateProposalBySigs(proposalId, sigs, txs.targets, txs.values, txs.signatures, txs.calldatas, '', ''); } @@ -373,8 +372,8 @@ contract UpdateProposalBySigsTest is NounsDAOLogicV3BaseTest { uint256[] memory expirationTimestamps ) = signersPKsExpirations(); - NounsDAOV3Proposals.ProposalTxs memory txs = makeTxs(makeAddr('new target'), 0, '', ''); - NounsDAOStorageV3.ProposerSignature[] memory sigs = makeUpdateProposalSigs( + NounsDAOProposals.ProposalTxs memory txs = makeTxs(makeAddr('new target'), 0, '', ''); + NounsDAOTypes.ProposerSignature[] memory sigs = makeUpdateProposalSigs( signers, signerPKs, expirationTimestamps, @@ -385,7 +384,7 @@ contract UpdateProposalBySigsTest is NounsDAOLogicV3BaseTest { sigs[1].signer = makeAddr('different signer'); vm.prank(proposer); - vm.expectRevert(abi.encodeWithSelector(NounsDAOV3Proposals.InvalidSignature.selector)); + vm.expectRevert(abi.encodeWithSelector(NounsDAOProposals.InvalidSignature.selector)); dao.updateProposalBySigs(proposalId, sigs, txs.targets, txs.values, txs.signatures, txs.calldatas, '', ''); } @@ -396,8 +395,8 @@ contract UpdateProposalBySigsTest is NounsDAOLogicV3BaseTest { uint256[] memory expirationTimestamps ) = signersPKsExpirations(); - NounsDAOV3Proposals.ProposalTxs memory txs = makeTxs(makeAddr('new target'), 0, '', ''); - NounsDAOStorageV3.ProposerSignature[] memory sigs = makeUpdateProposalSigs( + NounsDAOProposals.ProposalTxs memory txs = makeTxs(makeAddr('new target'), 0, '', ''); + NounsDAOTypes.ProposerSignature[] memory sigs = makeUpdateProposalSigs( signers, signerPKs, expirationTimestamps, @@ -407,7 +406,7 @@ contract UpdateProposalBySigsTest is NounsDAOLogicV3BaseTest { ); vm.prank(proposer); - vm.expectRevert(abi.encodeWithSelector(NounsDAOV3Proposals.InvalidSignature.selector)); + vm.expectRevert(abi.encodeWithSelector(NounsDAOProposals.InvalidSignature.selector)); dao.updateProposalBySigs(proposalId, sigs, txs.targets, txs.values, txs.signatures, txs.calldatas, '', ''); } @@ -418,8 +417,8 @@ contract UpdateProposalBySigsTest is NounsDAOLogicV3BaseTest { uint256[] memory expirationTimestamps ) = signersPKsExpirations(); - NounsDAOV3Proposals.ProposalTxs memory txs = makeTxs(makeAddr('new target'), 0, '', ''); - NounsDAOStorageV3.ProposerSignature[] memory sigs = makeUpdateProposalSigs( + NounsDAOProposals.ProposalTxs memory txs = makeTxs(makeAddr('new target'), 0, '', ''); + NounsDAOTypes.ProposerSignature[] memory sigs = makeUpdateProposalSigs( signers, signerPKs, expirationTimestamps, @@ -428,7 +427,7 @@ contract UpdateProposalBySigsTest is NounsDAOLogicV3BaseTest { ); vm.prank(proposer); - vm.expectRevert(abi.encodeWithSelector(NounsDAOV3Proposals.InvalidSignature.selector)); + vm.expectRevert(abi.encodeWithSelector(NounsDAOProposals.InvalidSignature.selector)); dao.updateProposalBySigs(proposalId, sigs, txs.targets, txs.values, txs.signatures, txs.calldatas, '', ''); } @@ -440,8 +439,8 @@ contract UpdateProposalBySigsTest is NounsDAOLogicV3BaseTest { uint256[] memory expirationTimestamps ) = signersPKsExpirations(); - NounsDAOV3Proposals.ProposalTxs memory txs = makeTxs(makeAddr('new target'), 0, '', ''); - NounsDAOStorageV3.ProposerSignature[] memory sigs = makeUpdateProposalSigs( + NounsDAOProposals.ProposalTxs memory txs = makeTxs(makeAddr('new target'), 0, '', ''); + NounsDAOTypes.ProposerSignature[] memory sigs = makeUpdateProposalSigs( signers, signerPKs, expirationTimestamps, @@ -453,7 +452,7 @@ contract UpdateProposalBySigsTest is NounsDAOLogicV3BaseTest { erc1271.setResponse(keccak256(sigs[1].sig), false); vm.prank(proposer); - vm.expectRevert(abi.encodeWithSelector(NounsDAOV3Proposals.InvalidSignature.selector)); + vm.expectRevert(abi.encodeWithSelector(NounsDAOProposals.InvalidSignature.selector)); dao.updateProposalBySigs(proposalId, sigs, txs.targets, txs.values, txs.signatures, txs.calldatas, '', ''); } @@ -464,8 +463,8 @@ contract UpdateProposalBySigsTest is NounsDAOLogicV3BaseTest { uint256[] memory expirationTimestamps ) = signersPKsExpirations(); - NounsDAOV3Proposals.ProposalTxs memory txs = makeTxs(makeAddr('new target'), 0, '', ''); - NounsDAOStorageV3.ProposerSignature[] memory sigs = makeUpdateProposalSigs( + NounsDAOProposals.ProposalTxs memory txs = makeTxs(makeAddr('new target'), 0, '', ''); + NounsDAOTypes.ProposerSignature[] memory sigs = makeUpdateProposalSigs( signers, signerPKs, expirationTimestamps, @@ -488,13 +487,13 @@ contract UpdateProposalBySigsTest is NounsDAOLogicV3BaseTest { uint256[] memory values = new uint256[](0); string[] memory signatures = new string[](0); bytes[] memory calldatas = new bytes[](0); - NounsDAOV3Proposals.ProposalTxs memory txs = NounsDAOV3Proposals.ProposalTxs( + NounsDAOProposals.ProposalTxs memory txs = NounsDAOProposals.ProposalTxs( targets, values, signatures, calldatas ); - NounsDAOStorageV3.ProposerSignature[] memory sigs = makeUpdateProposalSigs( + NounsDAOTypes.ProposerSignature[] memory sigs = makeUpdateProposalSigs( signers, signerPKs, expirationTimestamps, @@ -502,7 +501,7 @@ contract UpdateProposalBySigsTest is NounsDAOLogicV3BaseTest { address(dao) ); - vm.expectRevert(abi.encodeWithSelector(NounsDAOV3Proposals.MustProvideActions.selector)); + vm.expectRevert(abi.encodeWithSelector(NounsDAOProposals.MustProvideActions.selector)); dao.updateProposalBySigs(proposalId, sigs, txs.targets, txs.values, txs.signatures, txs.calldatas, '', ''); } @@ -523,13 +522,13 @@ contract UpdateProposalBySigsTest is NounsDAOLogicV3BaseTest { signatures[i] = ''; calldatas[i] = ''; } - NounsDAOV3Proposals.ProposalTxs memory txs = NounsDAOV3Proposals.ProposalTxs( + NounsDAOProposals.ProposalTxs memory txs = NounsDAOProposals.ProposalTxs( targets, values, signatures, calldatas ); - NounsDAOStorageV3.ProposerSignature[] memory sigs = makeUpdateProposalSigs( + NounsDAOTypes.ProposerSignature[] memory sigs = makeUpdateProposalSigs( signers, signerPKs, expirationTimestamps, @@ -537,7 +536,7 @@ contract UpdateProposalBySigsTest is NounsDAOLogicV3BaseTest { address(dao) ); - vm.expectRevert(abi.encodeWithSelector(NounsDAOV3Proposals.TooManyActions.selector)); + vm.expectRevert(abi.encodeWithSelector(NounsDAOProposals.TooManyActions.selector)); dao.updateProposalBySigs(proposalId, sigs, txs.targets, txs.values, txs.signatures, txs.calldatas, '', ''); } @@ -553,13 +552,13 @@ contract UpdateProposalBySigsTest is NounsDAOLogicV3BaseTest { uint256[] memory values = new uint256[](0); string[] memory signatures = new string[](0); bytes[] memory calldatas = new bytes[](0); - NounsDAOV3Proposals.ProposalTxs memory txs = NounsDAOV3Proposals.ProposalTxs( + NounsDAOProposals.ProposalTxs memory txs = NounsDAOProposals.ProposalTxs( targets, values, signatures, calldatas ); - NounsDAOStorageV3.ProposerSignature[] memory sigs = makeUpdateProposalSigs( + NounsDAOTypes.ProposerSignature[] memory sigs = makeUpdateProposalSigs( signers, signerPKs, expirationTimestamps, @@ -567,7 +566,7 @@ contract UpdateProposalBySigsTest is NounsDAOLogicV3BaseTest { address(dao) ); - vm.expectRevert(abi.encodeWithSelector(NounsDAOV3Proposals.ProposalInfoArityMismatch.selector)); + vm.expectRevert(abi.encodeWithSelector(NounsDAOProposals.ProposalInfoArityMismatch.selector)); dao.updateProposalBySigs(proposalId, sigs, txs.targets, txs.values, txs.signatures, txs.calldatas, '', ''); } @@ -577,8 +576,8 @@ contract UpdateProposalBySigsTest is NounsDAOLogicV3BaseTest { uint256[] memory signerPKs, uint256[] memory expirationTimestamps ) = signersPKsExpirations(); - NounsDAOV3Proposals.ProposalTxs memory txs = makeTxs(makeAddr('new target'), 0, '', ''); - NounsDAOStorageV3.ProposerSignature[] memory sigs = makeUpdateProposalSigs( + NounsDAOProposals.ProposalTxs memory txs = makeTxs(makeAddr('new target'), 0, '', ''); + NounsDAOTypes.ProposerSignature[] memory sigs = makeUpdateProposalSigs( signers, signerPKs, expirationTimestamps, @@ -588,14 +587,14 @@ contract UpdateProposalBySigsTest is NounsDAOLogicV3BaseTest { // Pending vm.roll(block.number + proposalUpdatablePeriodInBlocks); - assertTrue(dao.state(proposalId) == NounsDAOStorageV3.ProposalState.Pending); - vm.expectRevert(abi.encodeWithSelector(NounsDAOV3Proposals.CanOnlyEditUpdatableProposals.selector)); + assertTrue(dao.state(proposalId) == NounsDAOTypes.ProposalState.Pending); + vm.expectRevert(abi.encodeWithSelector(NounsDAOProposals.CanOnlyEditUpdatableProposals.selector)); dao.updateProposalBySigs(proposalId, sigs, txs.targets, txs.values, txs.signatures, txs.calldatas, '', ''); // Active vm.roll(block.number + VOTING_DELAY); - assertTrue(dao.state(proposalId) == NounsDAOStorageV3.ProposalState.Active); - vm.expectRevert(abi.encodeWithSelector(NounsDAOV3Proposals.CanOnlyEditUpdatableProposals.selector)); + assertTrue(dao.state(proposalId) == NounsDAOTypes.ProposalState.Active); + vm.expectRevert(abi.encodeWithSelector(NounsDAOProposals.CanOnlyEditUpdatableProposals.selector)); dao.updateProposalBySigs(proposalId, sigs, txs.targets, txs.values, txs.signatures, txs.calldatas, '', ''); // Succeeded @@ -604,21 +603,21 @@ contract UpdateProposalBySigsTest is NounsDAOLogicV3BaseTest { vm.prank(_signers[0]); dao.castVote(proposalId, 1); vm.roll(block.number + VOTING_PERIOD); - assertTrue(dao.state(proposalId) == NounsDAOStorageV3.ProposalState.Succeeded); - vm.expectRevert(abi.encodeWithSelector(NounsDAOV3Proposals.CanOnlyEditUpdatableProposals.selector)); + assertTrue(dao.state(proposalId) == NounsDAOTypes.ProposalState.Succeeded); + vm.expectRevert(abi.encodeWithSelector(NounsDAOProposals.CanOnlyEditUpdatableProposals.selector)); dao.updateProposalBySigs(proposalId, sigs, txs.targets, txs.values, txs.signatures, txs.calldatas, '', ''); // Queued dao.queue(proposalId); - assertTrue(dao.state(proposalId) == NounsDAOStorageV3.ProposalState.Queued); - vm.expectRevert(abi.encodeWithSelector(NounsDAOV3Proposals.CanOnlyEditUpdatableProposals.selector)); + assertTrue(dao.state(proposalId) == NounsDAOTypes.ProposalState.Queued); + vm.expectRevert(abi.encodeWithSelector(NounsDAOProposals.CanOnlyEditUpdatableProposals.selector)); dao.updateProposalBySigs(proposalId, sigs, txs.targets, txs.values, txs.signatures, txs.calldatas, '', ''); // Executed vm.warp(block.timestamp + TIMELOCK_DELAY); dao.execute(proposalId); - assertTrue(dao.state(proposalId) == NounsDAOStorageV3.ProposalState.Executed); - vm.expectRevert(abi.encodeWithSelector(NounsDAOV3Proposals.CanOnlyEditUpdatableProposals.selector)); + assertTrue(dao.state(proposalId) == NounsDAOTypes.ProposalState.Executed); + vm.expectRevert(abi.encodeWithSelector(NounsDAOProposals.CanOnlyEditUpdatableProposals.selector)); dao.updateProposalBySigs(proposalId, sigs, txs.targets, txs.values, txs.signatures, txs.calldatas, '', ''); } @@ -628,8 +627,8 @@ contract UpdateProposalBySigsTest is NounsDAOLogicV3BaseTest { uint256[] memory signerPKs, uint256[] memory expirationTimestamps ) = signersPKsExpirations(); - NounsDAOV3Proposals.ProposalTxs memory txs = makeTxs(makeAddr('new target'), 0, '', ''); - NounsDAOStorageV3.ProposerSignature[] memory sigs = makeUpdateProposalSigs( + NounsDAOProposals.ProposalTxs memory txs = makeTxs(makeAddr('new target'), 0, '', ''); + NounsDAOTypes.ProposerSignature[] memory sigs = makeUpdateProposalSigs( signers, signerPKs, expirationTimestamps, @@ -639,9 +638,9 @@ contract UpdateProposalBySigsTest is NounsDAOLogicV3BaseTest { vm.prank(proposer); dao.cancel(proposalId); - assertTrue(dao.state(proposalId) == NounsDAOStorageV3.ProposalState.Canceled); + assertTrue(dao.state(proposalId) == NounsDAOTypes.ProposalState.Canceled); - vm.expectRevert(abi.encodeWithSelector(NounsDAOV3Proposals.CanOnlyEditUpdatableProposals.selector)); + vm.expectRevert(abi.encodeWithSelector(NounsDAOProposals.CanOnlyEditUpdatableProposals.selector)); dao.updateProposalBySigs(proposalId, sigs, txs.targets, txs.values, txs.signatures, txs.calldatas, '', ''); } @@ -651,8 +650,8 @@ contract UpdateProposalBySigsTest is NounsDAOLogicV3BaseTest { uint256[] memory signerPKs, uint256[] memory expirationTimestamps ) = signersPKsExpirations(); - NounsDAOV3Proposals.ProposalTxs memory txs = makeTxs(makeAddr('new target'), 0, '', ''); - NounsDAOStorageV3.ProposerSignature[] memory sigs = makeUpdateProposalSigs( + NounsDAOProposals.ProposalTxs memory txs = makeTxs(makeAddr('new target'), 0, '', ''); + NounsDAOTypes.ProposerSignature[] memory sigs = makeUpdateProposalSigs( signers, signerPKs, expirationTimestamps, @@ -661,9 +660,9 @@ contract UpdateProposalBySigsTest is NounsDAOLogicV3BaseTest { ); vm.roll(block.number + proposalUpdatablePeriodInBlocks + VOTING_DELAY + VOTING_PERIOD); - assertTrue(dao.state(proposalId) == NounsDAOStorageV3.ProposalState.Defeated); + assertTrue(dao.state(proposalId) == NounsDAOTypes.ProposalState.Defeated); - vm.expectRevert(abi.encodeWithSelector(NounsDAOV3Proposals.CanOnlyEditUpdatableProposals.selector)); + vm.expectRevert(abi.encodeWithSelector(NounsDAOProposals.CanOnlyEditUpdatableProposals.selector)); dao.updateProposalBySigs(proposalId, sigs, txs.targets, txs.values, txs.signatures, txs.calldatas, '', ''); } @@ -673,8 +672,8 @@ contract UpdateProposalBySigsTest is NounsDAOLogicV3BaseTest { uint256[] memory signerPKs, uint256[] memory expirationTimestamps ) = signersPKsExpirations(); - NounsDAOV3Proposals.ProposalTxs memory txs = makeTxs(makeAddr('new target'), 0, '', ''); - NounsDAOStorageV3.ProposerSignature[] memory sigs = makeUpdateProposalSigs( + NounsDAOProposals.ProposalTxs memory txs = makeTxs(makeAddr('new target'), 0, '', ''); + NounsDAOTypes.ProposerSignature[] memory sigs = makeUpdateProposalSigs( signers, signerPKs, expirationTimestamps, @@ -690,9 +689,9 @@ contract UpdateProposalBySigsTest is NounsDAOLogicV3BaseTest { vm.roll(block.number + VOTING_PERIOD); dao.queue(proposalId); vm.warp(block.timestamp + TIMELOCK_DELAY + timelock.GRACE_PERIOD()); - assertTrue(dao.state(proposalId) == NounsDAOStorageV3.ProposalState.Expired); + assertTrue(dao.state(proposalId) == NounsDAOTypes.ProposalState.Expired); - vm.expectRevert(abi.encodeWithSelector(NounsDAOV3Proposals.CanOnlyEditUpdatableProposals.selector)); + vm.expectRevert(abi.encodeWithSelector(NounsDAOProposals.CanOnlyEditUpdatableProposals.selector)); dao.updateProposalBySigs(proposalId, sigs, txs.targets, txs.values, txs.signatures, txs.calldatas, '', ''); } @@ -702,8 +701,8 @@ contract UpdateProposalBySigsTest is NounsDAOLogicV3BaseTest { uint256[] memory signerPKs, uint256[] memory expirationTimestamps ) = signersPKsExpirations(); - NounsDAOV3Proposals.ProposalTxs memory txs = makeTxs(makeAddr('new target'), 0, '', ''); - NounsDAOStorageV3.ProposerSignature[] memory sigs = makeUpdateProposalSigs( + NounsDAOProposals.ProposalTxs memory txs = makeTxs(makeAddr('new target'), 0, '', ''); + NounsDAOTypes.ProposerSignature[] memory sigs = makeUpdateProposalSigs( signers, signerPKs, expirationTimestamps, @@ -713,9 +712,9 @@ contract UpdateProposalBySigsTest is NounsDAOLogicV3BaseTest { vm.prank(vetoer); dao.veto(proposalId); - assertTrue(dao.state(proposalId) == NounsDAOStorageV3.ProposalState.Vetoed); + assertTrue(dao.state(proposalId) == NounsDAOTypes.ProposalState.Vetoed); - vm.expectRevert(abi.encodeWithSelector(NounsDAOV3Proposals.CanOnlyEditUpdatableProposals.selector)); + vm.expectRevert(abi.encodeWithSelector(NounsDAOProposals.CanOnlyEditUpdatableProposals.selector)); dao.updateProposalBySigs(proposalId, sigs, txs.targets, txs.values, txs.signatures, txs.calldatas, '', ''); } @@ -725,8 +724,8 @@ contract UpdateProposalBySigsTest is NounsDAOLogicV3BaseTest { uint256[] memory signerPKs, uint256[] memory expirationTimestamps ) = signersPKsExpirations(); - NounsDAOV3Proposals.ProposalTxs memory txs = makeTxs(makeAddr('new target'), 0, '', ''); - NounsDAOStorageV3.ProposerSignature[] memory sigs = makeUpdateProposalSigs( + NounsDAOProposals.ProposalTxs memory txs = makeTxs(makeAddr('new target'), 0, '', ''); + NounsDAOTypes.ProposerSignature[] memory sigs = makeUpdateProposalSigs( signers, signerPKs, expirationTimestamps, @@ -742,9 +741,9 @@ contract UpdateProposalBySigsTest is NounsDAOLogicV3BaseTest { vm.prank(_signers[0]); dao.castVote(proposalId, 1); vm.roll(block.number + lastMinuteWindowInBlocks); - assertTrue(dao.state(proposalId) == NounsDAOStorageV3.ProposalState.ObjectionPeriod); + assertTrue(dao.state(proposalId) == NounsDAOTypes.ProposalState.ObjectionPeriod); - vm.expectRevert(abi.encodeWithSelector(NounsDAOV3Proposals.CanOnlyEditUpdatableProposals.selector)); + vm.expectRevert(abi.encodeWithSelector(NounsDAOProposals.CanOnlyEditUpdatableProposals.selector)); dao.updateProposalBySigs(proposalId, sigs, txs.targets, txs.values, txs.signatures, txs.calldatas, '', ''); } @@ -754,8 +753,8 @@ contract UpdateProposalBySigsTest is NounsDAOLogicV3BaseTest { uint256[] memory signerPKs, uint256[] memory expirationTimestamps ) = signersPKsExpirations(); - NounsDAOV3Proposals.ProposalTxs memory txs = makeTxs(makeAddr('new target'), 0, '', ''); - NounsDAOStorageV3.ProposerSignature[] memory sigs = makeUpdateProposalSigs( + NounsDAOProposals.ProposalTxs memory txs = makeTxs(makeAddr('new target'), 0, '', ''); + NounsDAOTypes.ProposerSignature[] memory sigs = makeUpdateProposalSigs( signers, signerPKs, expirationTimestamps, @@ -776,7 +775,7 @@ contract UpdateProposalBySigsTest is NounsDAOLogicV3BaseTest { proposalId = propose(proposer, makeAddr('target'), 0, '', '', ''); vm.roll(block.number + 1); - vm.expectRevert(abi.encodeWithSelector(NounsDAOV3Proposals.SignerCountMismtach.selector)); + vm.expectRevert(abi.encodeWithSelector(NounsDAOProposals.SignerCountMismtach.selector)); vm.prank(proposer); dao.updateProposalBySigs(proposalId, sigs, txs.targets, txs.values, txs.signatures, txs.calldatas, '', ''); } @@ -787,20 +786,15 @@ contract UpdateProposalBySigsTest is NounsDAOLogicV3BaseTest { uint256[] memory signerPKs, uint256[] memory expirationTimestamps ) = signersPKsExpirations(); - NounsDAOV3Proposals.ProposalTxs memory txs = makeTxs( - makeAddr('new target'), - 1, - 'new signature', - 'new calldata' - ); - NounsDAOStorageV3.ProposerSignature[] memory sigs = makeUpdateProposalSigs( + NounsDAOProposals.ProposalTxs memory txs = makeTxs(makeAddr('new target'), 1, 'new signature', 'new calldata'); + NounsDAOTypes.ProposerSignature[] memory sigs = makeUpdateProposalSigs( signers, signerPKs, expirationTimestamps, UpdateProposalParams(proposalId, proposer, txs, 'descriptionAfter'), address(dao) ); - assertTrue(dao.state(proposalId) == NounsDAOStorageV3.ProposalState.Updatable); + assertTrue(dao.state(proposalId) == NounsDAOTypes.ProposalState.Updatable); ( address[] memory targetsBefore, uint256[] memory valuesBefore, @@ -848,14 +842,12 @@ contract UpdateProposalBySigsTest is NounsDAOLogicV3BaseTest { assertEq(calldatasAfter[0], 'new calldata'); } - function signersPKsExpirations(uint256 len) + function signersPKsExpirations( + uint256 len + ) internal view - returns ( - address[] memory signers, - uint256[] memory signerPKs, - uint256[] memory expirationTimestamps - ) + returns (address[] memory signers, uint256[] memory signerPKs, uint256[] memory expirationTimestamps) { signers = new address[](len); signerPKs = new uint256[](len); @@ -871,11 +863,7 @@ contract UpdateProposalBySigsTest is NounsDAOLogicV3BaseTest { function signersPKsExpirations() internal view - returns ( - address[] memory signers, - uint256[] memory signerPKs, - uint256[] memory expirationTimestamps - ) + returns (address[] memory signers, uint256[] memory signerPKs, uint256[] memory expirationTimestamps) { return signersPKsExpirations(2); } @@ -883,11 +871,7 @@ contract UpdateProposalBySigsTest is NounsDAOLogicV3BaseTest { function fewerSignersPKsExpirations() internal view - returns ( - address[] memory signers, - uint256[] memory signerPKs, - uint256[] memory expirationTimestamps - ) + returns (address[] memory signers, uint256[] memory signerPKs, uint256[] memory expirationTimestamps) { return signersPKsExpirations(1); } @@ -895,11 +879,7 @@ contract UpdateProposalBySigsTest is NounsDAOLogicV3BaseTest { function moreSignersPKsExpirations() internal view - returns ( - address[] memory signers, - uint256[] memory signerPKs, - uint256[] memory expirationTimestamps - ) + returns (address[] memory signers, uint256[] memory signerPKs, uint256[] memory expirationTimestamps) { return signersPKsExpirations(3); } diff --git a/packages/nouns-contracts/test/foundry/NounsDAOLogicV3/Veto.t.sol b/packages/nouns-contracts/test/foundry/NounsDAOLogic/Veto.t.sol similarity index 73% rename from packages/nouns-contracts/test/foundry/NounsDAOLogicV3/Veto.t.sol rename to packages/nouns-contracts/test/foundry/NounsDAOLogic/Veto.t.sol index 0161fe2e6b..6854da51c2 100644 --- a/packages/nouns-contracts/test/foundry/NounsDAOLogicV3/Veto.t.sol +++ b/packages/nouns-contracts/test/foundry/NounsDAOLogic/Veto.t.sol @@ -2,12 +2,11 @@ pragma solidity ^0.8.19; import 'forge-std/Test.sol'; -import { NounsDAOLogicV3 } from '../../../contracts/governance/NounsDAOLogicV3.sol'; import { NounsDAOLogicSharedBaseTest } from '../helpers/NounsDAOLogicSharedBase.t.sol'; -import { NounsDAOStorageV3 } from '../../../contracts/governance/NounsDAOInterfaces.sol'; -import { NounsDAOV3Proposals } from '../../../contracts/governance/NounsDAOV3Proposals.sol'; -import { NounsDAOV3Admin } from '../../../contracts/governance/NounsDAOV3Admin.sol'; -import { INounsDAOShared } from '../helpers/INounsDAOShared.sol'; +import { NounsDAOTypes } from '../../../contracts/governance/NounsDAOInterfaces.sol'; +import { NounsDAOProposals } from '../../../contracts/governance/NounsDAOProposals.sol'; +import { NounsDAOAdmin } from '../../../contracts/governance/NounsDAOAdmin.sol'; +import { INounsDAOLogic } from '../../../contracts/interfaces/INounsDAOLogic.sol'; contract NounsDAOLogicV3VetoTest is NounsDAOLogicSharedBaseTest { event NewPendingVetoer(address oldPendingVetoer, address newPendingVetoer); @@ -42,7 +41,7 @@ contract NounsDAOLogicV3VetoTest is NounsDAOLogicSharedBaseTest { function test_veto_revertsForNonVetoer() public { uint256 proposalId = propose(address(0x1234), 100, '', ''); - vm.expectRevert(NounsDAOV3Proposals.VetoerOnly.selector); + vm.expectRevert(NounsDAOProposals.VetoerOnly.selector); daoProxy.veto(proposalId); } @@ -52,7 +51,7 @@ contract NounsDAOLogicV3VetoTest is NounsDAOLogicSharedBaseTest { vm.startPrank(vetoer); daoProxy._burnVetoPower(); - vm.expectRevert(NounsDAOV3Proposals.VetoerBurned.selector); + vm.expectRevert(NounsDAOProposals.VetoerBurned.selector); daoProxy.veto(proposalId); @@ -63,35 +62,35 @@ contract NounsDAOLogicV3VetoTest is NounsDAOLogicSharedBaseTest { uint256 proposalId = propose(address(0x1234), 100, '', ''); // Need to roll one block because in V3 on the proposal creation block the state is Updatable vm.roll(block.number + 1); - assertTrue(daoProxy.state(proposalId) == NounsDAOStorageV3.ProposalState.Pending); + assertTrue(daoProxy.state(proposalId) == NounsDAOTypes.ProposalState.Pending); vm.prank(vetoer); daoProxy.veto(proposalId); - assertTrue(daoProxy.state(proposalId) == NounsDAOStorageV3.ProposalState.Vetoed); + assertTrue(daoProxy.state(proposalId) == NounsDAOTypes.ProposalState.Vetoed); } function test_veto_worksForPropStateActive() public { uint256 proposalId = propose(address(0x1234), 100, '', ''); vm.roll(block.number + daoProxy.votingDelay() + 1); - assertTrue(daoProxy.state(proposalId) == NounsDAOStorageV3.ProposalState.Active); + assertTrue(daoProxy.state(proposalId) == NounsDAOTypes.ProposalState.Active); vm.prank(vetoer); daoProxy.veto(proposalId); - assertTrue(daoProxy.state(proposalId) == NounsDAOStorageV3.ProposalState.Vetoed); + assertTrue(daoProxy.state(proposalId) == NounsDAOTypes.ProposalState.Vetoed); } function test_veto_worksForPropStateCanceled() public { uint256 proposalId = propose(address(0x1234), 100, '', ''); vm.prank(proposer); daoProxy.cancel(proposalId); - assertTrue(daoProxy.state(proposalId) == NounsDAOStorageV3.ProposalState.Canceled); + assertTrue(daoProxy.state(proposalId) == NounsDAOTypes.ProposalState.Canceled); vm.prank(vetoer); daoProxy.veto(proposalId); - assertTrue(daoProxy.state(proposalId) == NounsDAOStorageV3.ProposalState.Vetoed); + assertTrue(daoProxy.state(proposalId) == NounsDAOTypes.ProposalState.Vetoed); } function test_veto_worksForPropStateDefeated() public { @@ -100,12 +99,12 @@ contract NounsDAOLogicV3VetoTest is NounsDAOLogicSharedBaseTest { vm.prank(proposer); daoProxy.castVote(proposalId, 0); vm.roll(block.number + daoProxy.votingPeriod() + 1); - assertTrue(daoProxy.state(proposalId) == NounsDAOStorageV3.ProposalState.Defeated); + assertTrue(daoProxy.state(proposalId) == NounsDAOTypes.ProposalState.Defeated); vm.prank(vetoer); daoProxy.veto(proposalId); - assertTrue(daoProxy.state(proposalId) == NounsDAOStorageV3.ProposalState.Vetoed); + assertTrue(daoProxy.state(proposalId) == NounsDAOTypes.ProposalState.Vetoed); } function test_veto_worksForPropStateSucceeded() public { @@ -114,12 +113,12 @@ contract NounsDAOLogicV3VetoTest is NounsDAOLogicSharedBaseTest { vm.prank(proposer); daoProxy.castVote(proposalId, 1); vm.roll(block.number + daoProxy.votingPeriod() + 1); - assertTrue(daoProxy.state(proposalId) == NounsDAOStorageV3.ProposalState.Succeeded); + assertTrue(daoProxy.state(proposalId) == NounsDAOTypes.ProposalState.Succeeded); vm.prank(vetoer); daoProxy.veto(proposalId); - assertTrue(daoProxy.state(proposalId) == NounsDAOStorageV3.ProposalState.Vetoed); + assertTrue(daoProxy.state(proposalId) == NounsDAOTypes.ProposalState.Vetoed); } function test_veto_worksForPropStateQueued() public { @@ -129,12 +128,12 @@ contract NounsDAOLogicV3VetoTest is NounsDAOLogicSharedBaseTest { daoProxy.castVote(proposalId, 1); vm.roll(block.number + daoProxy.votingPeriod() + 1); daoProxy.queue(proposalId); - assertTrue(daoProxy.state(proposalId) == NounsDAOStorageV3.ProposalState.Queued); + assertTrue(daoProxy.state(proposalId) == NounsDAOTypes.ProposalState.Queued); vm.prank(vetoer); daoProxy.veto(proposalId); - assertTrue(daoProxy.state(proposalId) == NounsDAOStorageV3.ProposalState.Vetoed); + assertTrue(daoProxy.state(proposalId) == NounsDAOTypes.ProposalState.Vetoed); } function test_veto_worksForPropStateExpired() public { @@ -145,12 +144,12 @@ contract NounsDAOLogicV3VetoTest is NounsDAOLogicSharedBaseTest { vm.roll(block.number + daoProxy.votingPeriod() + 1); daoProxy.queue(proposalId); vm.warp(block.timestamp + timelock.delay() + timelock.GRACE_PERIOD() + 1); - assertTrue(daoProxy.state(proposalId) == NounsDAOStorageV3.ProposalState.Expired); + assertTrue(daoProxy.state(proposalId) == NounsDAOTypes.ProposalState.Expired); vm.prank(vetoer); daoProxy.veto(proposalId); - assertTrue(daoProxy.state(proposalId) == NounsDAOStorageV3.ProposalState.Vetoed); + assertTrue(daoProxy.state(proposalId) == NounsDAOTypes.ProposalState.Vetoed); } function test_veto_revertsForPropStateExecuted() public { @@ -163,9 +162,9 @@ contract NounsDAOLogicV3VetoTest is NounsDAOLogicSharedBaseTest { daoProxy.queue(proposalId); vm.warp(block.timestamp + timelock.delay() + 1); daoProxy.execute(proposalId); - assertTrue(daoProxy.state(proposalId) == NounsDAOStorageV3.ProposalState.Executed); + assertTrue(daoProxy.state(proposalId) == NounsDAOTypes.ProposalState.Executed); - vm.expectRevert(NounsDAOV3Proposals.CantVetoExecutedProposal.selector); + vm.expectRevert(NounsDAOProposals.CantVetoExecutedProposal.selector); vm.prank(vetoer); daoProxy.veto(proposalId); } @@ -174,28 +173,28 @@ contract NounsDAOLogicV3VetoTest is NounsDAOLogicSharedBaseTest { uint256 proposalId = propose(address(0x1234), 100, '', ''); vm.prank(vetoer); daoProxy.veto(proposalId); - assertTrue(daoProxy.state(proposalId) == NounsDAOStorageV3.ProposalState.Vetoed); + assertTrue(daoProxy.state(proposalId) == NounsDAOTypes.ProposalState.Vetoed); vm.prank(vetoer); daoProxy.veto(proposalId); - assertTrue(daoProxy.state(proposalId) == NounsDAOStorageV3.ProposalState.Vetoed); + assertTrue(daoProxy.state(proposalId) == NounsDAOTypes.ProposalState.Vetoed); } function test_veto_worksForPropStateUpdatable() public { uint256 proposalId = propose(address(0x1234), 100, '', ''); - NounsDAOLogicV3 daoAsV3 = NounsDAOLogicV3(payable(address(daoProxy))); + INounsDAOLogic daoAsV3 = INounsDAOLogic(payable(address(daoProxy))); - assertTrue(daoAsV3.state(proposalId) == NounsDAOStorageV3.ProposalState.Updatable); + assertTrue(daoAsV3.state(proposalId) == NounsDAOTypes.ProposalState.Updatable); vm.prank(vetoer); daoAsV3.veto(proposalId); - assertTrue(daoAsV3.state(proposalId) == NounsDAOStorageV3.ProposalState.Vetoed); + assertTrue(daoAsV3.state(proposalId) == NounsDAOTypes.ProposalState.Vetoed); } function test_setPendingVetoer_failsIfNotCurrentVetoer() public { - vm.expectRevert(NounsDAOV3Proposals.VetoerOnly.selector); + vm.expectRevert(NounsDAOProposals.VetoerOnly.selector); daoProxy._setPendingVetoer(address(0x1234)); } @@ -218,7 +217,7 @@ contract NounsDAOLogicV3VetoTest is NounsDAOLogicSharedBaseTest { vm.prank(vetoer); daoProxy._setPendingVetoer(pendingVetoer); - vm.expectRevert(NounsDAOV3Admin.PendingVetoerOnly.selector); + vm.expectRevert(NounsDAOAdmin.PendingVetoerOnly.selector); daoProxy._acceptVetoer(); vm.prank(pendingVetoer); @@ -256,7 +255,7 @@ contract NounsDAOLogicV3VetoTest is NounsDAOLogicSharedBaseTest { daoProxy._burnVetoPower(); vm.prank(pendingVetoer); - vm.expectRevert(NounsDAOV3Admin.PendingVetoerOnly.selector); + vm.expectRevert(NounsDAOAdmin.PendingVetoerOnly.selector); daoProxy._acceptVetoer(); assertEq(daoProxy.pendingVetoer(), address(0)); @@ -266,7 +265,7 @@ contract NounsDAOLogicV3VetoTest is NounsDAOLogicSharedBaseTest { address timelock, address nounsToken, address vetoer - ) internal override returns (INounsDAOShared) { + ) internal override returns (INounsDAOLogic) { return _createDAOV3Proxy(timelock, nounsToken, vetoer); } diff --git a/packages/nouns-contracts/test/foundry/NounsDAOLogicV3/Withdraw.t.sol b/packages/nouns-contracts/test/foundry/NounsDAOLogic/Withdraw.t.sol similarity index 66% rename from packages/nouns-contracts/test/foundry/NounsDAOLogicV3/Withdraw.t.sol rename to packages/nouns-contracts/test/foundry/NounsDAOLogic/Withdraw.t.sol index 52aa872c1d..47d35e2b58 100644 --- a/packages/nouns-contracts/test/foundry/NounsDAOLogicV3/Withdraw.t.sol +++ b/packages/nouns-contracts/test/foundry/NounsDAOLogic/Withdraw.t.sol @@ -2,11 +2,11 @@ pragma solidity ^0.8.15; import 'forge-std/Test.sol'; -import { NounsDAOLogicV3BaseTest } from './NounsDAOLogicV3BaseTest.sol'; -import { NounsDAOStorageV3 } from '../../../contracts/governance/NounsDAOInterfaces.sol'; -import { NounsDAOV3Admin } from '../../../contracts/governance/NounsDAOV3Admin.sol'; +import { NounsDAOLogicBaseTest } from './NounsDAOLogicBaseTest.sol'; +import { NounsDAOTypes } from '../../../contracts/governance/NounsDAOInterfaces.sol'; +import { NounsDAOAdmin } from '../../../contracts/governance/NounsDAOAdmin.sol'; -contract WithdrawTest is NounsDAOLogicV3BaseTest { +contract WithdrawTest is NounsDAOLogicBaseTest { event Withdraw(uint256 amount, bool sent); function test_withdraw_worksForAdmin() public { @@ -25,7 +25,7 @@ contract WithdrawTest is NounsDAOLogicV3BaseTest { } function test_withdraw_revertsForNonAdmin() public { - vm.expectRevert(NounsDAOV3Admin.AdminOnly.selector); + vm.expectRevert(NounsDAOAdmin.AdminOnly.selector); dao._withdraw(); } } diff --git a/packages/nouns-contracts/test/foundry/NounsDAOLogicState.t.sol b/packages/nouns-contracts/test/foundry/NounsDAOLogicState.t.sol index 2fb60197f2..0e4e4d5830 100644 --- a/packages/nouns-contracts/test/foundry/NounsDAOLogicState.t.sol +++ b/packages/nouns-contracts/test/foundry/NounsDAOLogicState.t.sol @@ -2,12 +2,8 @@ pragma solidity ^0.8.15; import 'forge-std/Test.sol'; -import { INounsDAOShared } from './helpers/INounsDAOShared.sol'; -import { NounsDAOLogicV2 } from '../../contracts/governance/NounsDAOLogicV2.sol'; -import { NounsDAOLogicV3 } from '../../contracts/governance/NounsDAOLogicV3.sol'; -import { NounsDAOProxy } from '../../contracts/governance/NounsDAOProxy.sol'; -import { NounsDAOProxyV2 } from '../../contracts/governance/NounsDAOProxyV2.sol'; -import { NounsDAOStorageV2, NounsDAOStorageV3 } from '../../contracts/governance/NounsDAOInterfaces.sol'; +import { INounsDAOLogic } from '../../contracts/interfaces/INounsDAOLogic.sol'; +import { NounsDAOTypes } from '../../contracts/governance/NounsDAOInterfaces.sol'; import { NounsDescriptorV2 } from '../../contracts/NounsDescriptorV2.sol'; import { NounsToken } from '../../contracts/NounsToken.sol'; import { NounsSeeder } from '../../contracts/NounsSeeder.sol'; @@ -32,19 +28,19 @@ abstract contract NounsDAOLogicStateBaseTest is NounsDAOLogicSharedBaseTest { function testPendingGivenProposalJustCreated() public { uint256 proposalId = propose(address(0x1234), 100, '', ''); - uint256 state = uint256(NounsDAOLogicV3(payable(address(daoProxy))).state(proposalId)); + uint256 state = uint256(INounsDAOLogic(payable(address(daoProxy))).state(proposalId)); if (daoVersion() < 3) { - assertEq(state, uint256(NounsDAOStorageV3.ProposalState.Pending)); + assertEq(state, uint256(NounsDAOTypes.ProposalState.Pending)); } else { - assertEq(state, uint256(NounsDAOStorageV3.ProposalState.Updatable)); + assertEq(state, uint256(NounsDAOTypes.ProposalState.Updatable)); } } function testActiveGivenProposalPastVotingDelay() public { uint256 proposalId = propose(address(0x1234), 100, '', ''); vm.roll(block.number + daoProxy.votingDelay() + 1); - assertTrue(daoProxy.state(proposalId) == NounsDAOStorageV3.ProposalState.Active); + assertTrue(daoProxy.state(proposalId) == NounsDAOTypes.ProposalState.Active); } function testCanceledGivenCanceledProposal() public { @@ -52,14 +48,14 @@ abstract contract NounsDAOLogicStateBaseTest is NounsDAOLogicSharedBaseTest { vm.prank(proposer); daoProxy.cancel(proposalId); - assertTrue(daoProxy.state(proposalId) == NounsDAOStorageV3.ProposalState.Canceled); + assertTrue(daoProxy.state(proposalId) == NounsDAOTypes.ProposalState.Canceled); } function testDefeatedByRunningOutOfTime() public { uint256 proposalId = propose(address(0x1234), 100, '', ''); vm.roll(block.number + daoProxy.votingDelay() + daoProxy.votingPeriod() + 1); - assertTrue(daoProxy.state(proposalId) == NounsDAOStorageV3.ProposalState.Defeated); + assertTrue(daoProxy.state(proposalId) == NounsDAOTypes.ProposalState.Defeated); } function testDefeatedByVotingAgainst() public { @@ -74,7 +70,7 @@ abstract contract NounsDAOLogicStateBaseTest is NounsDAOLogicSharedBaseTest { vote(againstVoter, proposalId, 0); endVotingPeriod(); - assertTrue(daoProxy.state(proposalId) == NounsDAOStorageV3.ProposalState.Defeated); + assertTrue(daoProxy.state(proposalId) == NounsDAOTypes.ProposalState.Defeated); } function testSucceeded() public { @@ -89,14 +85,14 @@ abstract contract NounsDAOLogicStateBaseTest is NounsDAOLogicSharedBaseTest { vote(againstVoter, proposalId, 0); endVotingPeriod(); - assertTrue(daoProxy.state(proposalId) == NounsDAOStorageV3.ProposalState.Succeeded); + assertTrue(daoProxy.state(proposalId) == NounsDAOTypes.ProposalState.Succeeded); } function testQueueRevertsGivenDefeatedProposal() public { uint256 proposalId = propose(address(0x1234), 100, '', ''); vm.roll(block.number + daoProxy.votingDelay() + daoProxy.votingPeriod() + 1); - assertTrue(daoProxy.state(proposalId) == NounsDAOStorageV3.ProposalState.Defeated); + assertTrue(daoProxy.state(proposalId) == NounsDAOTypes.ProposalState.Defeated); vm.expectRevert('NounsDAO::queue: proposal can only be queued if it is succeeded'); daoProxy.queue(proposalId); @@ -107,7 +103,7 @@ abstract contract NounsDAOLogicStateBaseTest is NounsDAOLogicSharedBaseTest { vm.prank(proposer); daoProxy.cancel(proposalId); - assertTrue(daoProxy.state(proposalId) == NounsDAOStorageV3.ProposalState.Canceled); + assertTrue(daoProxy.state(proposalId) == NounsDAOTypes.ProposalState.Canceled); vm.expectRevert('NounsDAO::queue: proposal can only be queued if it is succeeded'); daoProxy.queue(proposalId); @@ -128,7 +124,7 @@ abstract contract NounsDAOLogicStateBaseTest is NounsDAOLogicSharedBaseTest { // anyone can queue daoProxy.queue(proposalId); - assertTrue(daoProxy.state(proposalId) == NounsDAOStorageV3.ProposalState.Queued); + assertTrue(daoProxy.state(proposalId) == NounsDAOTypes.ProposalState.Queued); } function testExpired() public { @@ -145,7 +141,7 @@ abstract contract NounsDAOLogicStateBaseTest is NounsDAOLogicSharedBaseTest { daoProxy.queue(proposalId); vm.warp(block.timestamp + timelock.delay() + timelock.GRACE_PERIOD() + 1); - assertTrue(daoProxy.state(proposalId) == NounsDAOStorageV3.ProposalState.Expired); + assertTrue(daoProxy.state(proposalId) == NounsDAOTypes.ProposalState.Expired); } function testExecutedOnlyAfterQueued() public { @@ -173,10 +169,10 @@ abstract contract NounsDAOLogicStateBaseTest is NounsDAOLogicSharedBaseTest { vm.deal(address(timelock), 100); daoProxy.execute(proposalId); - assertTrue(daoProxy.state(proposalId) == NounsDAOStorageV3.ProposalState.Executed); + assertTrue(daoProxy.state(proposalId) == NounsDAOTypes.ProposalState.Executed); vm.warp(block.timestamp + timelock.delay() + timelock.GRACE_PERIOD() + 1); - assertTrue(daoProxy.state(proposalId) == NounsDAOStorageV3.ProposalState.Executed); + assertTrue(daoProxy.state(proposalId) == NounsDAOTypes.ProposalState.Executed); } } @@ -185,12 +181,8 @@ contract NounsDAOLogicV1ForkStateTest is NounsDAOLogicStateBaseTest { return 1; } - function deployDAOProxy( - address, - address, - address - ) internal override returns (INounsDAOShared) { - return INounsDAOShared(address(deployForkDAOProxy())); + function deployDAOProxy(address, address, address) internal override returns (INounsDAOLogic) { + return INounsDAOLogic(address(deployForkDAOProxy())); } } @@ -199,7 +191,7 @@ contract NounsDAOLogicV3StateTest is NounsDAOLogicStateBaseTest { address timelock, address nounsToken, address vetoer - ) internal override returns (INounsDAOShared) { + ) internal override returns (INounsDAOLogic) { return _createDAOV3Proxy(timelock, nounsToken, vetoer); } diff --git a/packages/nouns-contracts/test/foundry/NounsDAOLogicV3/NounsDAOV3Admin.t.sol b/packages/nouns-contracts/test/foundry/NounsDAOLogicV3/NounsDAOV3Admin.t.sol deleted file mode 100644 index e7eea7275a..0000000000 --- a/packages/nouns-contracts/test/foundry/NounsDAOLogicV3/NounsDAOV3Admin.t.sol +++ /dev/null @@ -1,208 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0 -pragma solidity ^0.8.15; - -import 'forge-std/Test.sol'; -import { NounsDAOLogicV3BaseTest } from './NounsDAOLogicV3BaseTest.sol'; -import { NounsDAOV3Admin } from '../../../contracts/governance/NounsDAOV3Admin.sol'; -import { NounsDAOProxy } from '../../../contracts/governance/NounsDAOProxy.sol'; - -contract NounsDAOLogicV3AdminTest is NounsDAOLogicV3BaseTest { - event ForkPeriodSet(uint256 oldForkPeriod, uint256 newForkPeriod); - event ForkThresholdSet(uint256 oldForkThreshold, uint256 newForkThreshold); - event ERC20TokensToIncludeInForkSet(address[] oldErc20Tokens, address[] newErc20tokens); - event ObjectionPeriodDurationSet( - uint32 oldObjectionPeriodDurationInBlocks, - uint32 newObjectionPeriodDurationInBlocks - ); - event ProposalUpdatablePeriodSet( - uint32 oldProposalUpdatablePeriodInBlocks, - uint32 newProposalUpdatablePeriodInBlocks - ); - - address[] tokens; - - function test_setForkPeriod_onlyAdmin() public { - vm.expectRevert(NounsDAOV3Admin.AdminOnly.selector); - dao._setForkPeriod(8 days); - } - - function test_setForkPeriod_works() public { - vm.prank(address(dao.timelock())); - vm.expectEmit(true, true, true, true); - emit ForkPeriodSet(7 days, 8 days); - dao._setForkPeriod(8 days); - - assertEq(dao.forkPeriod(), 8 days); - } - - function test_setForkPeriod_limitedByUpperBound() public { - vm.startPrank(address(dao.timelock())); - - // doesn't revert - dao._setForkPeriod(14 days); - - vm.expectRevert(NounsDAOV3Admin.ForkPeriodTooLong.selector); - dao._setForkPeriod(14 days + 1); - } - - function test_setForkPeriod_limitedByLowerBound() public { - vm.startPrank(address(dao.timelock())); - - // doesn't revert - dao._setForkPeriod(2 days); - - vm.expectRevert(NounsDAOV3Admin.ForkPeriodTooShort.selector); - dao._setForkPeriod(2 days - 1); - } - - function test_setForkThresholdBPS_onlyAdmin() public { - vm.expectRevert(NounsDAOV3Admin.AdminOnly.selector); - dao._setForkThresholdBPS(2000); - } - - function test_setForkThresholdBPS_works() public { - vm.prank(address(dao.timelock())); - vm.expectEmit(true, true, true, true); - emit ForkThresholdSet(2000, 1234); - dao._setForkThresholdBPS(1234); - - assertEq(dao.forkThresholdBPS(), 1234); - } - - function test_setErc20TokensToIncludeInFork_onlyAdmin() public { - tokens = [address(1), address(2)]; - - vm.expectRevert(NounsDAOV3Admin.AdminOnly.selector); - dao._setErc20TokensToIncludeInFork(tokens); - } - - function test_setErc20TokensToIncludeInFork_works() public { - tokens = [address(1), address(2)]; - - vm.prank(address(dao.timelock())); - vm.expectEmit(true, true, true, true); - emit ERC20TokensToIncludeInForkSet(new address[](0), tokens); - dao._setErc20TokensToIncludeInFork(tokens); - - assertEq(dao.erc20TokensToIncludeInFork(), tokens); - } - - function test_setErc20TokensToIncludeInFork_allowsEmptyArray() public { - tokens = new address[](0); - - vm.prank(address(dao.timelock())); - vm.expectEmit(true, true, true, true); - emit ERC20TokensToIncludeInForkSet(new address[](0), tokens); - dao._setErc20TokensToIncludeInFork(tokens); - - assertEq(dao.erc20TokensToIncludeInFork(), tokens); - } - - function test_setErc20TokensToIncludeInFork_givenDuplicateAddressesInInput_reverts() public { - address[] memory tokens = new address[](2); - tokens[0] = address(42); - tokens[1] = address(42); - - vm.prank(address(dao.timelock())); - vm.expectRevert(NounsDAOV3Admin.DuplicateTokenAddress.selector); - dao._setErc20TokensToIncludeInFork(tokens); - } - - function test_setForkEscrow_onlyAdmin() public { - vm.expectRevert(NounsDAOV3Admin.AdminOnly.selector); - dao._setForkEscrow(address(1)); - } - - function test_setForkEscrow_works() public { - vm.prank(address(dao.timelock())); - dao._setForkEscrow(address(1)); - - assertEq(address(dao.forkEscrow()), address(1)); - } - - function test_setTimelocks_onlyAdmin() public { - vm.expectRevert(NounsDAOV3Admin.AdminOnly.selector); - dao._setTimelocksAndAdmin(address(1), address(2), address(3)); - } - - function test_setTimelocks_works() public { - vm.prank(address(dao.timelock())); - dao._setTimelocksAndAdmin(address(1), address(2), address(3)); - - assertEq(address(dao.timelock()), address(1)); - assertEq(address(dao.timelockV1()), address(2)); - assertEq(NounsDAOProxy(payable(address(dao))).admin(), address(3)); - } - - function test_setVoteSnapshotBlockSwitchProposalId_onlyAdmin() public { - vm.expectRevert(NounsDAOV3Admin.AdminOnly.selector); - dao._setVoteSnapshotBlockSwitchProposalId(); - } - - function test_setVoteSnapshotBlockSwitchProposalId_setsToNextProposalId() public { - // overwrite proposalCount - vm.store(address(dao), bytes32(uint256(8)), bytes32(uint256(100))); - - vm.prank(address(dao.timelock())); - dao._setVoteSnapshotBlockSwitchProposalId(); - - assertEq(dao.voteSnapshotBlockSwitchProposalId(), 101); - } - - function test_setVoteSnapshotBlockSwitchProposalId_revertsIfCalledTwice() public { - vm.prank(address(dao.timelock())); - dao._setVoteSnapshotBlockSwitchProposalId(); - - vm.prank(address(dao.timelock())); - vm.expectRevert(NounsDAOV3Admin.VoteSnapshotSwitchAlreadySet.selector); - dao._setVoteSnapshotBlockSwitchProposalId(); - } - - function test_setObjectionPeriodDurationInBlocks_onlyAdmin() public { - vm.expectRevert(NounsDAOV3Admin.AdminOnly.selector); - dao._setObjectionPeriodDurationInBlocks(3 days / 12); - } - - function test_setObjectionPeriodDurationInBlocks_worksForAdmin() public { - uint32 blocks = 3 days / 12; - vm.expectEmit(true, true, true, true); - emit ObjectionPeriodDurationSet(10, blocks); - - vm.prank(address(dao.timelock())); - dao._setObjectionPeriodDurationInBlocks(blocks); - - assertEq(dao.objectionPeriodDurationInBlocks(), blocks); - } - - function test_setObjectionPeriodDurationInBlocks_givenValueAboveUpperBound_reverts() public { - uint32 blocks = 8 days / 12; - - vm.prank(address(dao.timelock())); - vm.expectRevert(NounsDAOV3Admin.InvalidObjectionPeriodDurationInBlocks.selector); - dao._setObjectionPeriodDurationInBlocks(blocks); - } - - function test_setProposalUpdatablePeriodInBlocks_onlyAdmin() public { - vm.expectRevert(NounsDAOV3Admin.AdminOnly.selector); - dao._setProposalUpdatablePeriodInBlocks(3 days / 12); - } - - function test_setProposalUpdatablePeriodInBlocks_worksForAdmin() public { - uint32 blocks = 3 days / 12; - vm.expectEmit(true, true, true, true); - emit ProposalUpdatablePeriodSet(10, blocks); - - vm.prank(address(dao.timelock())); - dao._setProposalUpdatablePeriodInBlocks(blocks); - - assertEq(dao.proposalUpdatablePeriodInBlocks(), blocks); - } - - function test_setProposalUpdatablePeriodInBlocks_givenValueAboveUpperBound_reverts() public { - uint32 blocks = 8 days / 12; - - vm.prank(address(dao.timelock())); - vm.expectRevert(NounsDAOV3Admin.InvalidProposalUpdatablePeriodInBlocks.selector); - dao._setProposalUpdatablePeriodInBlocks(blocks); - } -} diff --git a/packages/nouns-contracts/test/foundry/NounsDAOLogicV3/Propose.t.sol b/packages/nouns-contracts/test/foundry/NounsDAOLogicV3/Propose.t.sol deleted file mode 100644 index e019ea9401..0000000000 --- a/packages/nouns-contracts/test/foundry/NounsDAOLogicV3/Propose.t.sol +++ /dev/null @@ -1,57 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0 -pragma solidity ^0.8.15; - -import 'forge-std/Test.sol'; -import { NounsDAOLogicV3BaseTest } from './NounsDAOLogicV3BaseTest.sol'; - -contract ProposeTest is NounsDAOLogicV3BaseTest { - address proposer = makeAddr('proposer'); - - function setUp() public override { - super.setUp(); - - vm.prank(address(dao.timelock())); - dao._setProposalThresholdBPS(1_000); - - for (uint256 i = 0; i < 10; i++) { - mintTo(proposer); - } - } - - function testEmits_ProposalCreatedWithRequirements() public { - address[] memory targets = new address[](1); - targets[0] = makeAddr('target'); - uint256[] memory values = new uint256[](1); - values[0] = 42; - string[] memory signatures = new string[](1); - signatures[0] = 'some signature'; - bytes[] memory calldatas = new bytes[](1); - calldatas[0] = ''; - - uint256 updatablePeriodEndBlock = block.number + dao.proposalUpdatablePeriodInBlocks(); - uint256 startBlock = updatablePeriodEndBlock + dao.votingDelay(); - uint256 endBlock = startBlock + dao.votingPeriod(); - - vm.expectEmit(true, true, true, true); - - emit ProposalCreatedWithRequirements( - 1, - proposer, - new address[](0), - targets, - values, - signatures, - calldatas, - startBlock, - endBlock, - updatablePeriodEndBlock, - 1, // prop threshold - dao.minQuorumVotes(), - 'some description' - ); - - vm.prank(proposer); - - dao.propose(targets, values, signatures, calldatas, 'some description'); - } -} diff --git a/packages/nouns-contracts/test/foundry/Upgrade/UpgradeMainnetFork.t.sol b/packages/nouns-contracts/test/foundry/Upgrade/UpgradeMainnetFork.t.sol new file mode 100644 index 0000000000..442b016ea4 --- /dev/null +++ b/packages/nouns-contracts/test/foundry/Upgrade/UpgradeMainnetFork.t.sol @@ -0,0 +1,367 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity ^0.8.19; + +import 'forge-std/Test.sol'; +import { Strings } from '@openzeppelin/contracts/utils/Strings.sol'; +import { NounsDAOLogicV4 } from '../../../contracts/governance/NounsDAOLogicV4.sol'; +import { ProposeDAOUpgradeMainnet } from '../../../script/DAOUpgrade/ProposeDAOUpgradeMainnet.s.sol'; +import { NounsToken } from '../../../contracts/NounsToken.sol'; +import { INounsDAOLogic } from '../../../contracts/interfaces/INounsDAOLogic.sol'; +import { NounsDAOTypes } from '../../../contracts/governance/NounsDAOInterfaces.sol'; +import { NounsDAOData } from '../../../contracts/governance/data/NounsDAOData.sol'; +import { DeployAuctionHouseV2Mainnet } from '../../../script/AuctionHouseV2/DeployAuctionHouseV2Mainnet.s.sol'; +import { NounsAuctionHouseV2 } from '../../../contracts/NounsAuctionHouseV2.sol'; +import { NounsAuctionHousePreV2Migration } from '../../../contracts/NounsAuctionHousePreV2Migration.sol'; +import { NounsAuctionHouse } from '../../../contracts/NounsAuctionHouse.sol'; + +abstract contract UpgradeMainnetForkBaseTest is Test { + address public constant NOUNDERS = 0x2573C60a6D127755aA2DC85e342F7da2378a0Cc5; + address public constant WHALE = 0x83fCFe8Ba2FEce9578F0BbaFeD4Ebf5E915045B9; + NounsToken public nouns = NounsToken(0x9C8fF314C9Bc7F6e59A9d9225Fb22946427eDC03); + INounsDAOLogic public constant NOUNS_DAO_PROXY_MAINNET = INounsDAOLogic(0x6f3E6272A167e8AcCb32072d08E0957F9c79223d); + address public constant CURRENT_DAO_IMPL = 0xe3caa436461DBa00CFBE1749148C9fa7FA1F5344; + address public constant NOUNS_DAO_DATA_PROXY = 0xf790A5f59678dd733fb3De93493A91f472ca1365; + address public constant AUCTION_HOUSE_PROXY_MAINNET = 0x830BD73E4184ceF73443C15111a1DF14e495C706; + address public constant AUCTION_HOUSE_PROXY_ADMIN_MAINNET = 0xC1C119932d78aB9080862C5fcb964029f086401e; + + address proposerAddr = vm.addr(0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb); + address origin = makeAddr('origin'); + address newLogic; + + address[] targets; + uint256[] values; + string[] signatures; + bytes[] calldatas; + + function setUp() public virtual { + vm.createSelectFork(vm.envString('RPC_MAINNET'), 19127187); + + // Get votes + vm.prank(NOUNDERS); + nouns.delegate(proposerAddr); + vm.roll(block.number + 1); + + vm.deal(address(NOUNS_DAO_PROXY_MAINNET), 100 ether); + vm.fee(50 gwei); + vm.txGasPrice(50 gwei); + } + + function propose( + address target, + uint256 value, + string memory signature, + bytes memory data + ) internal returns (uint256 proposalId) { + vm.prank(proposerAddr); + address[] memory targets = new address[](1); + targets[0] = target; + uint256[] memory values = new uint256[](1); + values[0] = value; + string[] memory signatures = new string[](1); + signatures[0] = signature; + bytes[] memory calldatas = new bytes[](1); + calldatas[0] = data; + proposalId = NOUNS_DAO_PROXY_MAINNET.propose(targets, values, signatures, calldatas, 'my proposal'); + } + + function propose( + address target, + uint256 value, + string memory signature, + bytes memory data, + uint32 clientId + ) internal returns (uint256 proposalId) { + vm.prank(proposerAddr); + address[] memory targets = new address[](1); + targets[0] = target; + uint256[] memory values = new uint256[](1); + values[0] = value; + string[] memory signatures = new string[](1); + signatures[0] = signature; + bytes[] memory calldatas = new bytes[](1); + calldatas[0] = data; + proposalId = NOUNS_DAO_PROXY_MAINNET.propose(targets, values, signatures, calldatas, 'my proposal', clientId); + } + + function voteAndExecuteProposal(uint256 proposalId) internal { + NounsDAOTypes.ProposalCondensedV2 memory propInfo = NOUNS_DAO_PROXY_MAINNET.proposals(proposalId); + + vm.roll(propInfo.startBlock + 1); + vm.prank(proposerAddr, origin); + NOUNS_DAO_PROXY_MAINNET.castRefundableVote(proposalId, 1); + vm.prank(WHALE, origin); + NOUNS_DAO_PROXY_MAINNET.castRefundableVote(proposalId, 1); + + vm.roll(propInfo.endBlock + 1); + NOUNS_DAO_PROXY_MAINNET.queue(proposalId); + + propInfo = NOUNS_DAO_PROXY_MAINNET.proposals(proposalId); + vm.warp(propInfo.eta + 1); + NOUNS_DAO_PROXY_MAINNET.execute(proposalId); + } +} + +contract DAOUpgradeMainnetForkTest is UpgradeMainnetForkBaseTest { + function setUp() public virtual override { + super.setUp(); + + // Deploy the latest DAO logic + vm.setEnv('DEPLOYER_PRIVATE_KEY', '0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'); + newLogic = address(new NounsDAOLogicV4()); + + // Propose the upgrade + vm.setEnv('PROPOSER_KEY', '0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb'); + vm.setEnv('DAO_V3_IMPL', Strings.toHexString(uint160(newLogic), 20)); + vm.setEnv('PROPOSAL_DESCRIPTION_FILE', 'test/foundry/Upgrade/proposal-description.txt'); + uint256 proposalId = new ProposeDAOUpgradeMainnet().run(); + + // Execute the upgrade + voteAndExecuteProposal(proposalId); + } + + function test_daoUpgradeWorked() public { + assertTrue(CURRENT_DAO_IMPL != NOUNS_DAO_PROXY_MAINNET.implementation()); + assertEq(newLogic, NOUNS_DAO_PROXY_MAINNET.implementation()); + } + + function test_givenRecentBitPacking_creationBlockAndProposalIdValuesAreLegit() public { + NounsDAOTypes.ProposalCondensedV3 memory prop = NOUNS_DAO_PROXY_MAINNET.proposalsV3(493); + + assertEq(prop.id, 493); + assertEq(prop.creationBlock, 19093670); + assertEq(getProposalDataForRewards(493).creationTimestamp, 0); + + prop = NOUNS_DAO_PROXY_MAINNET.proposalsV3(474); + + assertEq(prop.id, 474); + assertEq(prop.creationBlock, 18836862); + assertEq(getProposalDataForRewards(474).creationTimestamp, 0); + } + + function test_creationTimestampAndBlock_setOnNewProposals() public { + assertTrue(block.timestamp > 0); + assertTrue(block.number > 0); + uint256 proposalId = propose(address(NOUNS_DAO_PROXY_MAINNET), 0, '', ''); + + NounsDAOTypes.ProposalCondensedV3 memory prop = NOUNS_DAO_PROXY_MAINNET.proposalsV3(proposalId); + + assertEq(getProposalDataForRewards(proposalId).creationTimestamp, block.timestamp); + assertEq(prop.creationBlock, block.number); + } + + function test_adminFunctions_workUsingTheNewFallbackDesign() public { + uint256 currentForkPeriod = NOUNS_DAO_PROXY_MAINNET.forkPeriod(); + uint256 expectedForkPeriod = currentForkPeriod + 1; + + uint256 proposalId = propose( + address(NOUNS_DAO_PROXY_MAINNET), + 0, + '_setForkPeriod(uint256)', + abi.encode(expectedForkPeriod) + ); + voteAndExecuteProposal(proposalId); + + assertEq(expectedForkPeriod, NOUNS_DAO_PROXY_MAINNET.forkPeriod()); + + uint256 currentVotingDelay = NOUNS_DAO_PROXY_MAINNET.votingDelay(); + uint256 expectedVotingDelay = currentVotingDelay - 1; + + proposalId = propose( + address(NOUNS_DAO_PROXY_MAINNET), + 0, + '_setVotingDelay(uint256)', + abi.encode(expectedVotingDelay) + ); + voteAndExecuteProposal(proposalId); + + assertEq(expectedVotingDelay, NOUNS_DAO_PROXY_MAINNET.votingDelay()); + } + + function test_voteSnapshotBlockSwitchProposalId_zeroOutWorks() public { + assertNotEq(NOUNS_DAO_PROXY_MAINNET.voteSnapshotBlockSwitchProposalId(), 0); + + uint256 proposalId = propose( + address(NOUNS_DAO_PROXY_MAINNET), + 0, + '_zeroOutVoteSnapshotBlockSwitchProposalId()', + '' + ); + voteAndExecuteProposal(proposalId); + + assertEq(NOUNS_DAO_PROXY_MAINNET.voteSnapshotBlockSwitchProposalId(), 0); + } + + function test_clientId_savedOnProposals() public { + uint32 expectedClientId = 42; + uint256 proposalId = propose(address(NOUNS_DAO_PROXY_MAINNET), 0, '', '', expectedClientId); + + NounsDAOTypes.ProposalForRewards memory propsData = getProposalDataForRewards(proposalId); + assertEq(expectedClientId, propsData.clientId); + } + + function getProposalDataForRewards(uint256 proposalId) internal returns (NounsDAOTypes.ProposalForRewards memory) { + return + NOUNS_DAO_PROXY_MAINNET.proposalDataForRewards(proposalId, proposalId, 0, false, false, new uint32[](0))[0]; + } + + function test_clientId_savedOnVotes() public { + uint256 proposalId = propose(address(NOUNS_DAO_PROXY_MAINNET), 0, '', ''); + NounsDAOTypes.ProposalCondensedV2 memory propInfo = NOUNS_DAO_PROXY_MAINNET.proposals(proposalId); + vm.roll(propInfo.startBlock + 1); + + uint32 clientId1 = 42; + uint32 clientId2 = 142; + + vm.prank(proposerAddr, origin); + NOUNS_DAO_PROXY_MAINNET.castRefundableVote(proposalId, 1, clientId1); + vm.prank(WHALE, origin); + NOUNS_DAO_PROXY_MAINNET.castRefundableVote(proposalId, 1, clientId2); + + uint32[] memory clientIds = new uint32[](2); + clientIds[0] = clientId1; + clientIds[1] = clientId2; + + NounsDAOTypes.ProposalForRewards[] memory propsData = NOUNS_DAO_PROXY_MAINNET.proposalDataForRewards( + proposalId, + proposalId, + 0, + false, + false, + clientIds + ); + NounsDAOTypes.ClientVoteData[] memory voteData = propsData[0].voteData; + + assertEq(voteData[0].txs, 1); + assertEq(voteData[0].votes, nouns.getCurrentVotes(proposerAddr)); + assertEq(voteData[1].txs, 1); + assertEq(voteData[1].votes, nouns.getCurrentVotes(WHALE)); + } + + function test_nounsCandidatesUsingProposalsV3GetterWorks() public { + NounsDAOData d = NounsDAOData(NOUNS_DAO_DATA_PROXY); + address[] memory targets = new address[](1); + targets[0] = address(0); + uint256[] memory values = new uint256[](1); + values[0] = 0; + string[] memory signatures = new string[](1); + signatures[0] = ''; + bytes[] memory calldatas = new bytes[](1); + calldatas[0] = bytes(''); + vm.expectRevert(NounsDAOData.ProposalToUpdateMustBeUpdatable.selector); + d.createProposalCandidate{ value: 0.1 ether }(targets, values, signatures, calldatas, 'desc', 'slug', 400); + } +} + +contract AuctionHouseUpgradeMainnetForkTest is UpgradeMainnetForkBaseTest { + uint256 v1NounId; + uint256 v1Amount; + uint256 v1StartTime; + uint256 v1EndTime; + address v1Bidder; + bool v1Settled; + address v1NounsAddress; + address v1WethAddress; + address v1Owner; + uint256 v1Duration; + uint8 v1MinBidIncrementPercentage; + uint256 v1ReservePrice; + uint256 v1TimeBuffer; + + function setUp() public override { + super.setUp(); + + // Save AH V1 state before the upgrade + NounsAuctionHouse ahv1 = NounsAuctionHouse(AUCTION_HOUSE_PROXY_MAINNET); + (v1NounId, v1Amount, v1StartTime, v1EndTime, v1Bidder, v1Settled) = ahv1.auction(); + v1NounsAddress = address(ahv1.nouns()); + v1WethAddress = address(ahv1.weth()); + v1Owner = ahv1.owner(); + v1Duration = ahv1.duration(); + v1MinBidIncrementPercentage = ahv1.minBidIncrementPercentage(); + v1ReservePrice = ahv1.reservePrice(); + v1TimeBuffer = ahv1.timeBuffer(); + + // Propose and execute the upgrade proposal + + NounsAuctionHouseV2 newLogic = new NounsAuctionHouseV2(ahv1.nouns(), ahv1.weth(), ahv1.duration()); + NounsAuctionHousePreV2Migration migratorLogic = new NounsAuctionHousePreV2Migration(); + + uint256 txCount = 3; + address[] memory targets = new address[](txCount); + uint256[] memory values = new uint256[](txCount); + string[] memory signatures = new string[](txCount); + bytes[] memory calldatas = new bytes[](txCount); + + // proxyAdmin.upgrade(proxy, address(migratorLogic)); + targets[0] = AUCTION_HOUSE_PROXY_ADMIN_MAINNET; + signatures[0] = 'upgrade(address,address)'; + calldatas[0] = abi.encode(AUCTION_HOUSE_PROXY_MAINNET, address(migratorLogic)); + + // // migrator.migrate(); + targets[1] = AUCTION_HOUSE_PROXY_MAINNET; + signatures[1] = 'migrate()'; + + // proxyAdmin.upgrade(proxy, address(newLogic)); + targets[2] = AUCTION_HOUSE_PROXY_ADMIN_MAINNET; + signatures[2] = 'upgrade(address,address)'; + calldatas[2] = abi.encode(AUCTION_HOUSE_PROXY_MAINNET, address(newLogic)); + + vm.prank(proposerAddr); + uint256 proposalId = NOUNS_DAO_PROXY_MAINNET.propose( + targets, + values, + signatures, + calldatas, + 'Upgrading to AuctionHouseV2' + ); + + voteAndExecuteProposal(proposalId); + } + + function test_auctionState_survivesUpgrade() public { + NounsAuctionHouseV2 auctionV2 = NounsAuctionHouseV2(AUCTION_HOUSE_PROXY_MAINNET); + NounsAuctionHouseV2.AuctionV2View memory auctionV2State = auctionV2.auction(); + + assertEq(auctionV2State.nounId, v1NounId); + assertEq(auctionV2State.amount, v1Amount); + assertEq(auctionV2State.startTime, v1StartTime); + assertEq(auctionV2State.endTime, v1EndTime); + assertEq(auctionV2State.bidder, v1Bidder); + assertEq(auctionV2State.settled, false); + + assertEq(address(auctionV2.nouns()), v1NounsAddress); + assertEq(address(auctionV2.weth()), v1WethAddress); + assertEq(auctionV2.timeBuffer(), v1TimeBuffer); + assertEq(auctionV2.reservePrice(), v1ReservePrice); + assertEq(auctionV2.minBidIncrementPercentage(), v1MinBidIncrementPercentage); + assertEq(auctionV2.duration(), v1Duration); + assertEq(auctionV2.paused(), false); + assertEq(auctionV2.owner(), v1Owner); + } + + function test_bidAndSettleInV2_worksAndCapturesSettlementHistory() public { + NounsAuctionHouseV2 auctionV2 = NounsAuctionHouseV2(AUCTION_HOUSE_PROXY_MAINNET); + auctionV2.settleCurrentAndCreateNewAuction(); + uint32 clientId = 42; + uint96 nounId = auctionV2.auction().nounId; + + auctionV2.createBid{ value: 0.042 ether }(nounId, clientId); + vm.warp(block.timestamp + auctionV2.auction().endTime); + uint32 settlementTime = uint32(block.timestamp); + auctionV2.settleCurrentAndCreateNewAuction(); + + NounsAuctionHouseV2.Settlement[] memory settlements = auctionV2.getSettlementsFromIdtoTimestamp( + nounId, + block.timestamp, + true + ); + + assertEq(settlements.length, 1); + NounsAuctionHouseV2.Settlement memory s = settlements[0]; + assertEq(s.nounId, nounId); + assertEq(s.winner, address(this)); + assertEq(s.amount, 0.042 ether); + assertEq(s.clientId, clientId); + assertEq(s.blockTimestamp, settlementTime); + } +} diff --git a/packages/nouns-contracts/test/foundry/DAOUpgradeTo3p1/proposal-description.txt b/packages/nouns-contracts/test/foundry/Upgrade/proposal-description.txt similarity index 100% rename from packages/nouns-contracts/test/foundry/DAOUpgradeTo3p1/proposal-description.txt rename to packages/nouns-contracts/test/foundry/Upgrade/proposal-description.txt diff --git a/packages/nouns-contracts/test/foundry/governance/InflationHandling.t.sol b/packages/nouns-contracts/test/foundry/governance/InflationHandling.t.sol index a99e855780..022fb75f32 100644 --- a/packages/nouns-contracts/test/foundry/governance/InflationHandling.t.sol +++ b/packages/nouns-contracts/test/foundry/governance/InflationHandling.t.sol @@ -2,14 +2,15 @@ pragma solidity ^0.8.15; import 'forge-std/Test.sol'; -import { INounsDAOShared } from '../helpers/INounsDAOShared.sol'; +import { INounsDAOLogic } from '../../../contracts/interfaces/INounsDAOLogic.sol'; +import { NounsDAOProposals } from '../../../contracts/governance/NounsDAOProposals.sol'; import { NounsDAOLogicSharedBaseTest } from '../helpers/NounsDAOLogicSharedBase.t.sol'; -import { NounsDAOLogicV2 } from '../../../contracts/governance/NounsDAOLogicV2.sol'; -import { NounsDAOProxyV2 } from '../../../contracts/governance/NounsDAOProxyV2.sol'; -import { NounsDAOStorageV1, NounsDAOStorageV2 } from '../../../contracts/governance/NounsDAOInterfaces.sol'; +import { NounsDAOProxyV3 } from '../../../contracts/governance/NounsDAOProxyV3.sol'; +import { NounsDAOTypes } from '../../../contracts/governance/NounsDAOInterfaces.sol'; import { Utils } from '../helpers/Utils.sol'; +import { DeployUtilsV3 } from '../helpers/DeployUtilsV3.sol'; -abstract contract NounsDAOLogicV2InflationHandlingTest is NounsDAOLogicSharedBaseTest, Utils { +abstract contract NounsDAOLogicV3InflationHandlingTest is NounsDAOLogicSharedBaseTest, Utils { uint256 constant proposalThresholdBPS_ = 678; // 6.78% uint16 constant minQuorumVotesBPS = 1100; // 11% address tokenHolder; @@ -18,35 +19,32 @@ abstract contract NounsDAOLogicV2InflationHandlingTest is NounsDAOLogicSharedBas address user3; function daoVersion() internal pure override returns (uint256) { - return 2; + return 3; } function deployDAOProxy( address timelock, address nounsToken, address vetoer - ) internal override returns (INounsDAOShared) { - NounsDAOLogicV2 daoLogic = new NounsDAOLogicV2(); - + ) internal override returns (INounsDAOLogic) { return - INounsDAOShared( - address( - new NounsDAOProxyV2( - timelock, - nounsToken, - vetoer, - admin, - address(daoLogic), - votingPeriod, - votingDelay, - proposalThresholdBPS_, - NounsDAOStorageV2.DynamicQuorumParams({ - minQuorumVotesBPS: minQuorumVotesBPS, - maxQuorumVotesBPS: 2000, - quorumCoefficient: 10000 - }) - ) - ) + _createDAOV3Proxy( + timelock, + nounsToken, + vetoer, + NounsDAOTypes.NounsDAOParams({ + votingPeriod: votingPeriod, + votingDelay: votingDelay, + proposalThresholdBPS: proposalThresholdBPS_, + lastMinuteWindowInBlocks: LAST_MINUTE_BLOCKS, + objectionPeriodDurationInBlocks: OBJECTION_PERIOD_BLOCKS, + proposalUpdatablePeriodInBlocks: 0 + }), + NounsDAOTypes.DynamicQuorumParams({ + minQuorumVotesBPS: minQuorumVotesBPS, + maxQuorumVotesBPS: 2000, + quorumCoefficient: 10000 + }) ); } @@ -72,7 +70,7 @@ abstract contract NounsDAOLogicV2InflationHandlingTest is NounsDAOLogicSharedBas } } -contract NounsDAOLogicV2InflationHandling40TotalSupplyTest is NounsDAOLogicV2InflationHandlingTest { +contract NounsDAOLogic3InflationHandling40TotalSupplyTest is NounsDAOLogicV3InflationHandlingTest { function setUp() public virtual override { super.setUp(); @@ -82,7 +80,7 @@ contract NounsDAOLogicV2InflationHandling40TotalSupplyTest is NounsDAOLogicV2Inf function testSetsParametersCorrectly() public { assertEq(daoProxy.proposalThresholdBPS(), proposalThresholdBPS_); - assertEq(daoProxyAsV2().getDynamicQuorumParamsAt(block.number).minQuorumVotesBPS, minQuorumVotesBPS); + assertEq(daoProxy.getDynamicQuorumParamsAt(block.number).minQuorumVotesBPS, minQuorumVotesBPS); } function testProposalThresholdBasedOnTotalSupply() public { @@ -92,7 +90,7 @@ contract NounsDAOLogicV2InflationHandling40TotalSupplyTest is NounsDAOLogicV2Inf function testMinimumQuorumVotes() public { // 11% of 40 = 4.4, floored to 4 - assertEq(daoProxyAsV2().minQuorumVotes(), 4); + assertEq(daoProxy.minQuorumVotes(), 4); } function testRejectsIfProposingBelowThreshold() public { @@ -106,7 +104,7 @@ contract NounsDAOLogicV2InflationHandling40TotalSupplyTest is NounsDAOLogicV2Inf assertEq(nounsToken.getPriorVotes(user1, block.number - 1), 2); - vm.expectRevert('NounsDAO::propose: proposer votes below proposal threshold'); + vm.expectRevert(NounsDAOProposals.VotesBelowProposalThreshold.selector); propose(user1, address(0), 0, '', ''); } @@ -126,7 +124,7 @@ contract NounsDAOLogicV2InflationHandling40TotalSupplyTest is NounsDAOLogicV2Inf } } -abstract contract TotalSupply40WithAProposalState is NounsDAOLogicV2InflationHandlingTest { +abstract contract TotalSupply40WithAProposalState is NounsDAOLogicV3InflationHandlingTest { uint256 proposalId; function setUp() public virtual override { @@ -163,8 +161,8 @@ abstract contract TotalSupply40WithAProposalState is NounsDAOLogicV2InflationHan contract InflationHandlingWithAProposalTest is TotalSupply40WithAProposalState { function testSetsProposalAttrbiutesCorrectly() public { - assertEq(daoProxyAsV2().proposals(proposalId).proposalThreshold, 2); - assertEq(daoProxyAsV2().proposals(proposalId).quorumVotes, 4); + assertEq(daoProxy.proposals(proposalId).proposalThreshold, 2); + assertEq(daoProxy.proposals(proposalId).quorumVotes, 4); } } @@ -181,17 +179,17 @@ contract SupplyIncreasedStateTest is SupplyIncreasedState { assertEq(daoProxy.proposalThreshold(), 5); // 11% of 80 = 8.88, floored to 8 - assertEq(daoProxyAsV2().minQuorumVotes(), 8); + assertEq(daoProxy.minQuorumVotes(), 8); } function testRejectsProposalsPreviouslyAboveThresholdButNowBelowBecauseSupplyIncreased() public { - vm.expectRevert('NounsDAO::propose: proposer votes below proposal threshold'); + vm.expectRevert(NounsDAOProposals.VotesBelowProposalThreshold.selector); propose(user1, address(0), 0, '', ''); } function testDoesntChangePreviousProposalAttributes() public { - assertEq(daoProxyAsV2().proposals(proposalId).proposalThreshold, 2); - assertEq(daoProxyAsV2().proposals(proposalId).quorumVotes, 4); + assertEq(daoProxy.proposals(proposalId).proposalThreshold, 2); + assertEq(daoProxy.proposals(proposalId).quorumVotes, 4); } function testProposalPassesWhenForVotesAboveQuorumAndAgainstVotes() public { @@ -204,11 +202,11 @@ contract SupplyIncreasedStateTest is SupplyIncreasedState { vm.prank(user3); daoProxy.castVote(proposalId, 0); // 5 votes - assertEq(daoProxyAsV2().proposals(proposalId).forVotes, 6); - assertEq(daoProxyAsV2().proposals(proposalId).againstVotes, 5); + assertEq(daoProxy.proposals(proposalId).forVotes, 6); + assertEq(daoProxy.proposals(proposalId).againstVotes, 5); vm.roll(block.number + votingPeriod); - assertEq(uint256(daoProxy.state(proposalId)), uint256(NounsDAOStorageV1.ProposalState.Succeeded)); + assertEq(uint256(daoProxy.state(proposalId)), uint256(NounsDAOTypes.ProposalState.Succeeded)); } } diff --git a/packages/nouns-contracts/test/foundry/governance/NounsDAOLogicV3GasSnapshot.t.sol b/packages/nouns-contracts/test/foundry/governance/NounsDAOLogicV3GasSnapshot.t.sol index fd756d67ee..d65fc69a1e 100644 --- a/packages/nouns-contracts/test/foundry/governance/NounsDAOLogicV3GasSnapshot.t.sol +++ b/packages/nouns-contracts/test/foundry/governance/NounsDAOLogicV3GasSnapshot.t.sol @@ -4,13 +4,10 @@ pragma solidity ^0.8.15; import 'forge-std/Test.sol'; import { NounsDAOLogicSharedBaseTest } from '../helpers/NounsDAOLogicSharedBase.t.sol'; -import { INounsDAOShared } from '../helpers/INounsDAOShared.sol'; +import { INounsDAOLogic } from '../../../contracts/interfaces/INounsDAOLogic.sol'; import { DeployUtilsV3 } from '../helpers/DeployUtilsV3.sol'; -import { NounsDAOLogicV2 } from '../../../contracts/governance/NounsDAOLogicV2.sol'; -import { NounsDAOLogicV3 } from '../../../contracts/governance/NounsDAOLogicV3.sol'; -import { NounsDAOProxyV2 } from '../../../contracts/governance/NounsDAOProxyV2.sol'; import { NounsDAOProxyV3 } from '../../../contracts/governance/NounsDAOProxyV3.sol'; -import { NounsDAOStorageV2, NounsDAOStorageV3 } from '../../../contracts/governance/NounsDAOInterfaces.sol'; +import { NounsDAOTypes } from '../../../contracts/governance/NounsDAOInterfaces.sol'; abstract contract NounsDAOLogic_GasSnapshot_propose is NounsDAOLogicSharedBaseTest { address immutable target = makeAddr('target'); @@ -51,7 +48,7 @@ abstract contract NounsDAOLogic_GasSnapshot_propose is NounsDAOLogicSharedBaseTe daoProxy.propose(targets, values, signatures, calldatas, getLongDescription()); } - function getLongDescription() internal returns (string memory) { + function getLongDescription() internal view returns (string memory) { return vm.readFile('./test/foundry/files/longProposalDescription.txt'); } } @@ -155,38 +152,22 @@ contract NounsDAOLogic_GasSnapshot_V3_propose is DeployUtilsV3, NounsDAOLogic_Ga address timelock, address nounsToken, address vetoer - ) internal override returns (INounsDAOShared) { + ) internal override returns (INounsDAOLogic) { return _createDAOV3Proxy(timelock, nounsToken, vetoer); } } -contract NounsDAOLogic_GasSnapshot_V2_propose is DeployUtilsV3, NounsDAOLogic_GasSnapshot_propose { - function deployDAOProxy( - address timelock, - address nounsToken, - address vetoer - ) internal override returns (INounsDAOShared) { - return _createDAOV2Proxy(timelock, nounsToken, vetoer); - } -} - contract NounsDAOLogic_GasSnapshot_V3_vote is DeployUtilsV3, NounsDAOLogic_GasSnapshot_castVote { function deployDAOProxy( address timelock, address nounsToken, address vetoer - ) internal override returns (INounsDAOShared) { + ) internal override returns (INounsDAOLogic) { return _createDAOV3Proxy(timelock, nounsToken, vetoer); } -} -contract NounsDAOLogic_GasSnapshot_V2_vote is DeployUtilsV3, NounsDAOLogic_GasSnapshot_castVote { - function deployDAOProxy( - address timelock, - address nounsToken, - address vetoer - ) internal override returns (INounsDAOShared) { - return _createDAOV2Proxy(timelock, nounsToken, vetoer); + function test_proposalsV3() public view { + daoProxy.proposalsV3(1); } } @@ -198,7 +179,7 @@ contract NounsDAOLogic_GasSnapshot_V3_voteDuringObjectionPeriod is address timelock, address nounsToken, address vetoer - ) internal override returns (INounsDAOShared) { + ) internal override returns (INounsDAOLogic) { return _createDAOV3Proxy(timelock, nounsToken, vetoer); } } diff --git a/packages/nouns-contracts/test/foundry/governance/fork/ForkingEndToEnd.t.sol b/packages/nouns-contracts/test/foundry/governance/fork/ForkingEndToEnd.t.sol index 081a10cb68..43ba5dff52 100644 --- a/packages/nouns-contracts/test/foundry/governance/fork/ForkingEndToEnd.t.sol +++ b/packages/nouns-contracts/test/foundry/governance/fork/ForkingEndToEnd.t.sol @@ -4,7 +4,6 @@ pragma solidity ^0.8.15; import 'forge-std/Test.sol'; import { DeployUtilsFork } from '../../helpers/DeployUtilsFork.sol'; -import { NounsDAOLogicV3 } from '../../../../contracts/governance/NounsDAOLogicV3.sol'; import { NounsToken } from '../../../../contracts/NounsToken.sol'; import { NounsTokenFork } from '../../../../contracts/governance/fork/newdao/token/NounsTokenFork.sol'; import { NounsDAOExecutorV2 } from '../../../../contracts/governance/NounsDAOExecutorV2.sol'; @@ -12,10 +11,11 @@ import { NounsDAOLogicV1Fork } from '../../../../contracts/governance/fork/newda import { NounsAuctionHouseFork } from '../../../../contracts/governance/fork/newdao/NounsAuctionHouseFork.sol'; import { NounsTokenLike } from '../../../../contracts/governance/NounsDAOInterfaces.sol'; import { INounsAuctionHouse } from '../../../../contracts/interfaces/INounsAuctionHouse.sol'; +import { INounsDAOLogic } from '../../../../contracts/interfaces/INounsDAOLogic.sol'; contract ForkingHappyFlowTest is DeployUtilsFork { address minter; - NounsDAOLogicV3 daoV3; + INounsDAOLogic daoV3; NounsToken ogToken; NounsTokenFork forkToken; NounsDAOExecutorV2 forkTreasury; @@ -170,7 +170,7 @@ contract ForkingHappyFlowTest is DeployUtilsFork { } abstract contract ForkDAOBase is DeployUtilsFork { - NounsDAOLogicV3 originalDAO; + INounsDAOLogic originalDAO; NounsTokenLike originalToken; NounsDAOLogicV1Fork forkDAO; NounsDAOExecutorV2 forkTreasury; diff --git a/packages/nouns-contracts/test/foundry/governance/fork/NounsDAOLogicV1Fork.t.sol b/packages/nouns-contracts/test/foundry/governance/fork/NounsDAOLogicV1Fork.t.sol index 5e51d08413..deff7d0d10 100644 --- a/packages/nouns-contracts/test/foundry/governance/fork/NounsDAOLogicV1Fork.t.sol +++ b/packages/nouns-contracts/test/foundry/governance/fork/NounsDAOLogicV1Fork.t.sol @@ -5,7 +5,6 @@ import 'forge-std/Test.sol'; import 'forge-std/Base.sol'; import { DeployUtilsFork } from '../../helpers/DeployUtilsFork.sol'; -import { NounsDAOLogicV3 } from '../../../../contracts/governance/NounsDAOLogicV3.sol'; import { NounsToken } from '../../../../contracts/NounsToken.sol'; import { NounsTokenFork } from '../../../../contracts/governance/fork/newdao/token/NounsTokenFork.sol'; import { NounsDAOExecutorV2 } from '../../../../contracts/governance/NounsDAOExecutorV2.sol'; @@ -18,6 +17,7 @@ import { ERC20Mock, IERC20Receiver } from '../../helpers/ERC20Mock.sol'; import { MaliciousForkDAOQuitter } from '../../helpers/MaliciousForkDAOQuitter.sol'; import { NounsAuctionHouse } from '../../../../contracts/NounsAuctionHouse.sol'; import { INounsAuctionHouse } from '../../../../contracts/interfaces/INounsAuctionHouse.sol'; +import { INounsDAOLogic } from '../../../../contracts/interfaces/INounsDAOLogic.sol'; abstract contract NounsDAOLogicV1ForkBase is DeployUtilsFork { NounsDAOLogicV1Fork dao; @@ -203,7 +203,7 @@ contract NounsDAOLogicV1Fork_cancelProposalUnderThresholdBugFix_Test is NounsDAO abstract contract ForkWithEscrow is NounsDAOLogicV1ForkBase { NounsDAOForkEscrowMock escrow; NounsTokenLike originalToken; - NounsDAOLogicV3 originalDAO; + INounsDAOLogic originalDAO; address owner1 = makeAddr('owner1'); diff --git a/packages/nouns-contracts/test/foundry/governance/fork/NounsTokenFork.t.sol b/packages/nouns-contracts/test/foundry/governance/fork/NounsTokenFork.t.sol index 97aff68a6d..35c9f11c97 100644 --- a/packages/nouns-contracts/test/foundry/governance/fork/NounsTokenFork.t.sol +++ b/packages/nouns-contracts/test/foundry/governance/fork/NounsTokenFork.t.sol @@ -186,14 +186,7 @@ contract NounsTokenFork_DelegateBySig_Test is NounsTokenForkBase { uint256 nonce, uint256 expiry, uint256 pk - ) - internal - returns ( - uint8 v, - bytes32 r, - bytes32 s - ) - { + ) internal view returns (uint8 v, bytes32 r, bytes32 s) { bytes32 domainSeparator = keccak256( abi.encode( keccak256('EIP712Domain(string name,uint256 chainId,address verifyingContract)'), diff --git a/packages/nouns-contracts/test/foundry/helpers/AuctionHelpers.sol b/packages/nouns-contracts/test/foundry/helpers/AuctionHelpers.sol new file mode 100644 index 0000000000..608b16bca9 --- /dev/null +++ b/packages/nouns-contracts/test/foundry/helpers/AuctionHelpers.sol @@ -0,0 +1,37 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity ^0.8.19; + +import 'forge-std/Base.sol'; +import { INounsAuctionHouse } from '../../../contracts/interfaces/INounsAuctionHouse.sol'; + +abstract contract AuctionHelpers is CommonBase { + function bidAndSettleAuction(INounsAuctionHouse auctionHouse, address buyer) internal { + INounsAuctionHouse.Auction memory auction = getAuction(auctionHouse); + if (auction.endTime < block.timestamp) { + auctionHouse.settleCurrentAndCreateNewAuction(); + auction = getAuction(auctionHouse); + } + + vm.deal(buyer, buyer.balance + 0.1 ether); + vm.startPrank(buyer); + uint256 newNounId = auction.nounId; + auctionHouse.createBid{ value: 0.1 ether }(newNounId); + vm.warp(block.timestamp + auction.endTime); + auctionHouse.settleCurrentAndCreateNewAuction(); + vm.roll(block.number + 1); + vm.stopPrank(); + } + + function getAuction(INounsAuctionHouse auctionHouse) internal view returns (INounsAuctionHouse.Auction memory) { + ( + uint256 nounId, + uint256 amount, + uint256 startTime, + uint256 endTime, + address payable bidder, + bool settled + ) = auctionHouse.auction(); + + return INounsAuctionHouse.Auction(nounId, amount, startTime, endTime, bidder, settled); + } +} diff --git a/packages/nouns-contracts/test/foundry/helpers/AuctionHouseUpgrader.sol b/packages/nouns-contracts/test/foundry/helpers/AuctionHouseUpgrader.sol new file mode 100644 index 0000000000..6c70290b5c --- /dev/null +++ b/packages/nouns-contracts/test/foundry/helpers/AuctionHouseUpgrader.sol @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity ^0.8.19; + +import { NounsAuctionHouse } from '../../../contracts/NounsAuctionHouse.sol'; +import { NounsAuctionHouseV2 } from '../../../contracts/NounsAuctionHouseV2.sol'; +import { NounsAuctionHousePreV2Migration } from '../../../contracts/NounsAuctionHousePreV2Migration.sol'; +import { NounsAuctionHouseProxy } from '../../../contracts/proxies/NounsAuctionHouseProxy.sol'; +import { NounsAuctionHouseProxyAdmin } from '../../../contracts/proxies/NounsAuctionHouseProxyAdmin.sol'; +import 'forge-std/Vm.sol'; + +library AuctionHouseUpgrader { + Vm private constant vm = Vm(address(uint160(uint256(keccak256('hevm cheat code'))))); + + function upgradeAuctionHouse( + address owner, + NounsAuctionHouseProxyAdmin proxyAdmin, + NounsAuctionHouseProxy proxy + ) internal { + NounsAuctionHouse auctionV1 = NounsAuctionHouse(address(proxy)); + + NounsAuctionHouseV2 newLogic = new NounsAuctionHouseV2( + auctionV1.nouns(), + auctionV1.weth(), + auctionV1.duration() + ); + NounsAuctionHousePreV2Migration migratorLogic = new NounsAuctionHousePreV2Migration(); + + vm.startPrank(owner); + + // not using upgradeAndCall because the call must come from the auction house owner + // which is owner, not the proxy admin + + proxyAdmin.upgrade(proxy, address(migratorLogic)); + NounsAuctionHousePreV2Migration migrator = NounsAuctionHousePreV2Migration(address(proxy)); + migrator.migrate(); + proxyAdmin.upgrade(proxy, address(newLogic)); + + vm.stopPrank(); + } +} diff --git a/packages/nouns-contracts/test/foundry/helpers/BidderWithGasGriefing.sol b/packages/nouns-contracts/test/foundry/helpers/BidderWithGasGriefing.sol new file mode 100644 index 0000000000..50a59e1bca --- /dev/null +++ b/packages/nouns-contracts/test/foundry/helpers/BidderWithGasGriefing.sol @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity ^0.8.6; + +import { NounsAuctionHouseV2 } from '../../../contracts/NounsAuctionHouseV2.sol'; + +contract BidderWithGasGriefing { + function bid(NounsAuctionHouseV2 auctionHouse, uint256 nounId) public payable { + auctionHouse.createBid{ value: msg.value }(nounId); + } + + receive() external payable { + assembly { + return(0, 107744) + } + } +} diff --git a/packages/nouns-contracts/test/foundry/helpers/DeployUtils.sol b/packages/nouns-contracts/test/foundry/helpers/DeployUtils.sol index b5aff8a781..1544da9773 100644 --- a/packages/nouns-contracts/test/foundry/helpers/DeployUtils.sol +++ b/packages/nouns-contracts/test/foundry/helpers/DeployUtils.sol @@ -2,24 +2,21 @@ pragma solidity ^0.8.19; import 'forge-std/Test.sol'; -import { INounsDAOShared } from './INounsDAOShared.sol'; +import { INounsDAOLogic } from '../../../contracts/interfaces/INounsDAOLogic.sol'; import { DescriptorHelpers } from './DescriptorHelpers.sol'; import { NounsDescriptorV2 } from '../../../contracts/NounsDescriptorV2.sol'; import { SVGRenderer } from '../../../contracts/SVGRenderer.sol'; import { NounsArt } from '../../../contracts/NounsArt.sol'; import { NounsDAOExecutor } from '../../../contracts/governance/NounsDAOExecutor.sol'; -import { NounsDAOLogicV2 } from '../../../contracts/governance/NounsDAOLogicV2.sol'; import { IProxyRegistry } from '../../../contracts/external/opensea/IProxyRegistry.sol'; import { NounsDescriptor } from '../../../contracts/NounsDescriptor.sol'; import { NounsSeeder } from '../../../contracts/NounsSeeder.sol'; import { NounsToken } from '../../../contracts/NounsToken.sol'; -import { NounsDAOProxy } from '../../../contracts/governance/NounsDAOProxy.sol'; -import { NounsDAOStorageV2 } from '../../../contracts/governance/NounsDAOInterfaces.sol'; -import { NounsDAOProxyV2 } from '../../../contracts/governance/NounsDAOProxyV2.sol'; import { Inflator } from '../../../contracts/Inflator.sol'; -import { NounsAuctionHouse } from '../../../contracts/NounsAuctionHouse.sol'; import { NounsAuctionHouseProxy } from '../../../contracts/proxies/NounsAuctionHouseProxy.sol'; import { NounsAuctionHouseProxyAdmin } from '../../../contracts/proxies/NounsAuctionHouseProxyAdmin.sol'; +import { NounsAuctionHouse } from '../../../contracts/NounsAuctionHouse.sol'; +import { WETH } from '../../../contracts/test/WETH.sol'; abstract contract DeployUtils is Test, DescriptorHelpers { uint256 constant TIMELOCK_DELAY = 2 days; @@ -27,6 +24,40 @@ abstract contract DeployUtils is Test, DescriptorHelpers { uint256 constant VOTING_DELAY = 1; uint256 constant PROPOSAL_THRESHOLD = 1; uint256 constant QUORUM_VOTES_BPS = 2000; + uint256 constant AUCTION_TIME_BUFFER = 5 minutes; + uint256 constant AUCTION_RESERVE_PRICE = 1; + uint8 constant AUCTION_MIN_BID_INCREMENT_PRCT = 2; + uint256 constant AUCTION_DURATION = 24 hours; + + function _deployAuctionHouseV1AndToken( + address owner, + address noundersDAO, + address minter + ) internal returns (NounsAuctionHouseProxy, NounsAuctionHouseProxyAdmin) { + NounsAuctionHouse logic = new NounsAuctionHouse(); + NounsToken token = deployToken(noundersDAO, minter); + WETH weth = new WETH(); + NounsAuctionHouseProxyAdmin admin = new NounsAuctionHouseProxyAdmin(); + admin.transferOwnership(owner); + + bytes memory data = abi.encodeWithSelector( + NounsAuctionHouse.initialize.selector, + address(token), + address(weth), + AUCTION_TIME_BUFFER, + AUCTION_RESERVE_PRICE, + AUCTION_MIN_BID_INCREMENT_PRCT, + AUCTION_DURATION + ); + NounsAuctionHouseProxy proxy = new NounsAuctionHouseProxy(address(logic), address(admin), data); + NounsAuctionHouse auction = NounsAuctionHouse(address(proxy)); + + auction.transferOwnership(owner); + token.setMinter(address(proxy)); + + return (proxy, admin); + } + uint32 constant LAST_MINUTE_BLOCKS = 10; uint32 constant OBJECTION_PERIOD_BLOCKS = 10; uint32 constant UPDATABLE_PERIOD_BLOCKS = 10; @@ -59,100 +90,14 @@ abstract contract DeployUtils is Test, DescriptorHelpers { return descriptorV2; } - function _deployTokenAndDAOAndPopulateDescriptor( - address noundersDAO, - address vetoer, - address minter - ) internal returns (address, address) { + function deployToken(address noundersDAO, address minter) internal returns (NounsToken nounsToken) { IProxyRegistry proxyRegistry = IProxyRegistry(address(3)); - - NounsDAOExecutor timelock = new NounsDAOExecutor(address(1), TIMELOCK_DELAY); - NounsDescriptor descriptor = new NounsDescriptor(); - NounsToken nounsToken = new NounsToken(noundersDAO, minter, descriptor, new NounsSeeder(), proxyRegistry); - NounsDAOProxy proxy = new NounsDAOProxy( - address(timelock), - address(nounsToken), - vetoer, - address(timelock), - address(new NounsDAOLogicV2()), - VOTING_PERIOD, - VOTING_DELAY, - PROPOSAL_THRESHOLD, - QUORUM_VOTES_BPS - ); - - vm.prank(address(timelock)); - timelock.setPendingAdmin(address(proxy)); - vm.prank(address(proxy)); - timelock.acceptAdmin(); - - nounsToken.transferOwnership(address(timelock)); - - _populateDescriptor(descriptor); - - return (address(nounsToken), address(proxy)); - } - - function _createDAOV2Proxy( - address timelock, - address nounsToken, - address vetoer - ) internal returns (INounsDAOShared) { - return - INounsDAOShared( - address( - new NounsDAOProxyV2( - timelock, - nounsToken, - vetoer, - timelock, - address(new NounsDAOLogicV2()), - VOTING_PERIOD, - VOTING_DELAY, - PROPOSAL_THRESHOLD, - NounsDAOStorageV2.DynamicQuorumParams({ - minQuorumVotesBPS: 200, - maxQuorumVotesBPS: 2000, - quorumCoefficient: 10000 - }) - ) - ) - ); - } - - function deployDAOV2() internal returns (NounsDAOLogicV2) { - NounsDAOExecutor timelock = new NounsDAOExecutor(address(1), TIMELOCK_DELAY); - - NounsAuctionHouse auctionLogic = new NounsAuctionHouse(); - NounsAuctionHouseProxyAdmin auctionAdmin = new NounsAuctionHouseProxyAdmin(); - NounsAuctionHouseProxy auctionProxy = new NounsAuctionHouseProxy( - address(auctionLogic), - address(auctionAdmin), - '' - ); - auctionAdmin.transferOwnership(address(timelock)); - NounsDescriptorV2 descriptor = _deployAndPopulateV2(); - NounsToken nounsToken = new NounsToken( - makeAddr('noundersDAO'), - address(auctionProxy), - descriptor, - new NounsSeeder(), - IProxyRegistry(address(0)) - ); - INounsDAOShared daoProxy = _createDAOV2Proxy(address(timelock), address(nounsToken), makeAddr('vetoer')); - - vm.prank(address(timelock)); - timelock.setPendingAdmin(address(daoProxy)); - vm.prank(address(daoProxy)); - timelock.acceptAdmin(); - - nounsToken.transferOwnership(address(timelock)); - return NounsDAOLogicV2(payable(address(daoProxy))); + nounsToken = new NounsToken(noundersDAO, minter, descriptor, new NounsSeeder(), proxyRegistry); } - function get1967Implementation(address proxy) internal returns (address) { + function get1967Implementation(address proxy) internal view returns (address) { bytes32 slot = bytes32(uint256(keccak256('eip1967.proxy.implementation')) - 1); return address(uint160(uint256(vm.load(proxy, slot)))); } diff --git a/packages/nouns-contracts/test/foundry/helpers/DeployUtilsFork.sol b/packages/nouns-contracts/test/foundry/helpers/DeployUtilsFork.sol index 890cc11ee9..d69d9a82cc 100644 --- a/packages/nouns-contracts/test/foundry/helpers/DeployUtilsFork.sol +++ b/packages/nouns-contracts/test/foundry/helpers/DeployUtilsFork.sol @@ -3,23 +3,16 @@ pragma solidity ^0.8.19; import 'forge-std/Test.sol'; import { DeployUtilsV3 } from './DeployUtilsV3.sol'; -import { NounsDAOLogicV3 } from '../../../contracts/governance/NounsDAOLogicV3.sol'; import { NounsDAOExecutorV2 } from '../../../contracts/governance/NounsDAOExecutorV2.sol'; import { ForkDAODeployer } from '../../../contracts/governance/fork/ForkDAODeployer.sol'; import { NounsTokenFork } from '../../../contracts/governance/fork/newdao/token/NounsTokenFork.sol'; import { NounsAuctionHouseFork } from '../../../contracts/governance/fork/newdao/NounsAuctionHouseFork.sol'; import { NounsDAOLogicV1Fork } from '../../../contracts/governance/fork/newdao/governance/NounsDAOLogicV1Fork.sol'; import { INounsDAOForkEscrow } from '../../../contracts/governance/NounsDAOInterfaces.sol'; +import { INounsDAOLogic } from '../../../contracts/interfaces/INounsDAOLogic.sol'; abstract contract DeployUtilsFork is DeployUtilsV3 { - function _deployForkDAO(INounsDAOForkEscrow escrow) - public - returns ( - address treasury, - address token, - address dao - ) - { + function _deployForkDAO(INounsDAOForkEscrow escrow) public returns (address treasury, address token, address dao) { ForkDAODeployer deployer = new ForkDAODeployer( address(new NounsTokenFork()), address(new NounsAuctionHouseFork()), @@ -36,15 +29,8 @@ abstract contract DeployUtilsFork is DeployUtilsV3 { dao = NounsDAOExecutorV2(payable(treasury)).admin(); } - function _deployForkDAO() - public - returns ( - address treasury, - address token, - address dao - ) - { - NounsDAOLogicV3 originalDAO = _deployDAOV3(); + function _deployForkDAO() public returns (address treasury, address token, address dao) { + INounsDAOLogic originalDAO = _deployDAOV3(); return _deployForkDAO(originalDAO.forkEscrow()); } } diff --git a/packages/nouns-contracts/test/foundry/helpers/DeployUtilsV3.sol b/packages/nouns-contracts/test/foundry/helpers/DeployUtilsV3.sol index 9218b83713..d292131734 100644 --- a/packages/nouns-contracts/test/foundry/helpers/DeployUtilsV3.sol +++ b/packages/nouns-contracts/test/foundry/helpers/DeployUtilsV3.sol @@ -3,8 +3,8 @@ pragma solidity ^0.8.19; import 'forge-std/Test.sol'; import { DeployUtils } from './DeployUtils.sol'; -import { INounsDAOShared } from './INounsDAOShared.sol'; -import { NounsDAOLogicV3 } from '../../../contracts/governance/NounsDAOLogicV3.sol'; +import { INounsDAOLogic } from '../../../contracts/interfaces/INounsDAOLogic.sol'; +import { NounsDAOLogicV4 } from '../../../contracts/governance/NounsDAOLogicV4.sol'; import { NounsDAOProxyV3 } from '../../../contracts/governance/NounsDAOProxyV3.sol'; import { NounsDAOForkEscrow } from '../../../contracts/governance/fork/NounsDAOForkEscrow.sol'; import { NounsDAOExecutorV2 } from '../../../contracts/governance/NounsDAOExecutorV2.sol'; @@ -19,17 +19,22 @@ import { ForkDAODeployer } from '../../../contracts/governance/fork/ForkDAODeplo import { NounsTokenFork } from '../../../contracts/governance/fork/newdao/token/NounsTokenFork.sol'; import { NounsAuctionHouseFork } from '../../../contracts/governance/fork/newdao/NounsAuctionHouseFork.sol'; import { NounsDAOLogicV1Fork } from '../../../contracts/governance/fork/newdao/governance/NounsDAOLogicV1Fork.sol'; -import { NounsDAOStorageV3 } from '../../../contracts/governance/NounsDAOInterfaces.sol'; +import { NounsDAOTypes } from '../../../contracts/governance/NounsDAOInterfaces.sol'; +import { INounsDAOLogic } from '../../../contracts/interfaces/INounsDAOLogic.sol'; abstract contract DeployUtilsV3 is DeployUtils { + NounsAuctionHouseProxyAdmin auctionHouseProxyAdmin; + function _createDAOV3Proxy( address timelock, address nounsToken, - address vetoer - ) internal returns (INounsDAOShared dao) { + address vetoer, + NounsDAOTypes.NounsDAOParams memory daoParams, + NounsDAOTypes.DynamicQuorumParams memory dqParams + ) internal returns (INounsDAOLogic dao) { uint256 nonce = vm.getNonce(address(this)); address predictedForkEscrowAddress = computeCreateAddress(address(this), nonce + 2); - dao = INounsDAOShared( + dao = INounsDAOLogic( address( new NounsDAOProxyV3( timelock, @@ -38,53 +43,67 @@ abstract contract DeployUtilsV3 is DeployUtils { address(0), vetoer, timelock, - address(new NounsDAOLogicV3()), - NounsDAOStorageV3.NounsDAOParams({ - votingPeriod: VOTING_PERIOD, - votingDelay: VOTING_DELAY, - proposalThresholdBPS: PROPOSAL_THRESHOLD, - lastMinuteWindowInBlocks: LAST_MINUTE_BLOCKS, - objectionPeriodDurationInBlocks: OBJECTION_PERIOD_BLOCKS, - proposalUpdatablePeriodInBlocks: 0 - }), - NounsDAOStorageV3.DynamicQuorumParams({ - minQuorumVotesBPS: 200, - maxQuorumVotesBPS: 2000, - quorumCoefficient: 10000 - }) + address(new NounsDAOLogicV4()), + daoParams, + dqParams ) ) ); address(new NounsDAOForkEscrow(address(dao), address(nounsToken))); } - function _deployDAOV3() internal returns (NounsDAOLogicV3) { - address noundersDAO = makeAddr('noundersDAO'); - address vetoer = makeAddr('vetoer'); - - NounsDAOExecutorV2 timelock = NounsDAOExecutorV2( - payable(address(new ERC1967Proxy(address(new NounsDAOExecutorV2()), ''))) + function _createDAOV3Proxy( + address timelock, + address nounsToken, + address vetoer + ) internal returns (INounsDAOLogic dao) { + dao = _createDAOV3Proxy( + timelock, + nounsToken, + vetoer, + NounsDAOTypes.NounsDAOParams({ + votingPeriod: VOTING_PERIOD, + votingDelay: VOTING_DELAY, + proposalThresholdBPS: PROPOSAL_THRESHOLD, + lastMinuteWindowInBlocks: LAST_MINUTE_BLOCKS, + objectionPeriodDurationInBlocks: OBJECTION_PERIOD_BLOCKS, + proposalUpdatablePeriodInBlocks: 0 + }), + NounsDAOTypes.DynamicQuorumParams({ + minQuorumVotesBPS: 200, + maxQuorumVotesBPS: 2000, + quorumCoefficient: 10000 + }) ); - timelock.initialize(address(1), TIMELOCK_DELAY); + } + + struct Temp { + NounsDAOExecutorV2 timelock; + NounsToken nounsToken; + } + + function _deployDAOV3WithParams(uint256 auctionDuration) internal returns (INounsDAOLogic) { + Temp memory t; + t.timelock = NounsDAOExecutorV2(payable(address(new ERC1967Proxy(address(new NounsDAOExecutorV2()), '')))); + t.timelock.initialize(address(1), TIMELOCK_DELAY); - NounsAuctionHouse auctionLogic = new NounsAuctionHouse(); - NounsAuctionHouseProxyAdmin auctionAdmin = new NounsAuctionHouseProxyAdmin(); + auctionHouseProxyAdmin = new NounsAuctionHouseProxyAdmin(); NounsAuctionHouseProxy auctionProxy = new NounsAuctionHouseProxy( - address(auctionLogic), - address(auctionAdmin), + address(new NounsAuctionHouse()), + address(auctionHouseProxyAdmin), '' ); - auctionAdmin.transferOwnership(address(timelock)); + auctionHouseProxyAdmin.transferOwnership(address(t.timelock)); - NounsToken nounsToken = new NounsToken( - noundersDAO, + t.nounsToken = new NounsToken( + makeAddr('noundersDAO'), address(auctionProxy), _deployAndPopulateV2(), new NounsSeeder(), new ProxyRegistryMock() ); - nounsToken.transferOwnership(address(timelock)); - address daoLogicImplementation = address(new NounsDAOLogicV3()); + t.nounsToken.transferOwnership(address(t.timelock)); + address daoLogicImplementation = address(new NounsDAOLogicV4()); uint256 nonce = vm.getNonce(address(this)); address predictedForkEscrowAddress = computeCreateAddress(address(this), nonce + 6); @@ -101,17 +120,17 @@ abstract contract DeployUtilsV3 is DeployUtils { FORK_DAO_QUORUM_VOTES_BPS ); - NounsDAOLogicV3 dao = NounsDAOLogicV3( + INounsDAOLogic dao = INounsDAOLogic( payable( new NounsDAOProxyV3( - address(timelock), - address(nounsToken), + address(t.timelock), + address(t.nounsToken), predictedForkEscrowAddress, address(forkDeployer), - vetoer, - address(timelock), + makeAddr('vetoer'), + address(t.timelock), daoLogicImplementation, - NounsDAOStorageV3.NounsDAOParams({ + NounsDAOTypes.NounsDAOParams({ votingPeriod: VOTING_PERIOD, votingDelay: VOTING_DELAY, proposalThresholdBPS: PROPOSAL_THRESHOLD, @@ -119,7 +138,7 @@ abstract contract DeployUtilsV3 is DeployUtils { objectionPeriodDurationInBlocks: OBJECTION_PERIOD_BLOCKS, proposalUpdatablePeriodInBlocks: UPDATABLE_PERIOD_BLOCKS }), - NounsDAOStorageV3.DynamicQuorumParams({ + NounsDAOTypes.DynamicQuorumParams({ minQuorumVotesBPS: 200, maxQuorumVotesBPS: 2000, quorumCoefficient: 10000 @@ -128,21 +147,25 @@ abstract contract DeployUtilsV3 is DeployUtils { ) ); - address(new NounsDAOForkEscrow(address(dao), address(nounsToken))); + address(new NounsDAOForkEscrow(address(dao), address(t.nounsToken))); - vm.prank(address(timelock)); - NounsAuctionHouse(address(auctionProxy)).initialize(nounsToken, makeAddr('weth'), 2, 0, 1, 10 minutes); + vm.prank(address(t.timelock)); + NounsAuctionHouse(address(auctionProxy)).initialize(t.nounsToken, makeAddr('weth'), 2, 0, 1, auctionDuration); - vm.prank(address(timelock)); - timelock.setPendingAdmin(address(dao)); + vm.prank(address(t.timelock)); + t.timelock.setPendingAdmin(address(dao)); vm.prank(address(dao)); - timelock.acceptAdmin(); + t.timelock.acceptAdmin(); - vm.startPrank(address(timelock)); + vm.startPrank(address(t.timelock)); dao._setForkPeriod(FORK_PERIOD); dao._setForkThresholdBPS(FORK_THRESHOLD_BPS); vm.stopPrank(); return dao; } + + function _deployDAOV3() internal returns (INounsDAOLogic) { + return _deployDAOV3WithParams(10 minutes); + } } diff --git a/packages/nouns-contracts/test/foundry/helpers/INounsDAOShared.sol b/packages/nouns-contracts/test/foundry/helpers/INounsDAOShared.sol deleted file mode 100644 index a7c35dd189..0000000000 --- a/packages/nouns-contracts/test/foundry/helpers/INounsDAOShared.sol +++ /dev/null @@ -1,66 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0 -pragma solidity ^0.8.19; - -import { NounsDAOStorageV3 } from '../../../contracts/governance/NounsDAOInterfaces.sol'; - -interface INounsDAOShared { - function propose( - address[] memory targets, - uint256[] memory values, - string[] memory signatures, - bytes[] memory calldatas, - string memory description - ) external returns (uint256); - - function queue(uint256 proposalId) external; - - function execute(uint256 proposalId) external; - - function cancel(uint256 proposalId) external; - - function castVote(uint256 proposalId, uint8 support) external; - - function castRefundableVote(uint256 proposalId, uint8 support) external; - - function castVoteWithReason( - uint256 proposalId, - uint8 support, - string memory reason - ) external; - - function veto(uint256 proposalId) external; - - function state(uint256 proposalId) external view returns (NounsDAOStorageV3.ProposalState); - - function timelock() external view returns (address); - - function votingDelay() external view returns (uint256); - - function votingPeriod() external view returns (uint256); - - function proposalThresholdBPS() external view returns (uint256); - - function proposalThreshold() external view returns (uint256); - - function vetoer() external view returns (address); - - function _setVotingPeriod(uint256 votingPeriod_) external; - - function _setVotingDelay(uint256 votingDelay_) external; - - function _setProposalThresholdBPS(uint256 proposalThresholdBPS_) external; - - function _setQuorumVotesBPS(uint256 quorumVotesBPS_) external; - - function _burnVetoPower() external; - - function _setPendingVetoer(address pendingVetoer_) external; - - function pendingVetoer() external view returns (address); - - function _acceptVetoer() external; - - function proposalsV3(uint256 proposalId) external view returns (NounsDAOStorageV3.ProposalCondensed memory); - - function implementation() external view returns (address); -} diff --git a/packages/nouns-contracts/test/foundry/helpers/NounsDAOLogicSharedBase.t.sol b/packages/nouns-contracts/test/foundry/helpers/NounsDAOLogicSharedBase.t.sol index f790b4b799..c5e672fbd9 100644 --- a/packages/nouns-contracts/test/foundry/helpers/NounsDAOLogicSharedBase.t.sol +++ b/packages/nouns-contracts/test/foundry/helpers/NounsDAOLogicSharedBase.t.sol @@ -2,10 +2,7 @@ pragma solidity ^0.8.15; import 'forge-std/Test.sol'; -import { INounsDAOShared } from './INounsDAOShared.sol'; -import { NounsDAOLogicV2 } from '../../../contracts/governance/NounsDAOLogicV2.sol'; -import { NounsDAOProxy } from '../../../contracts/governance/NounsDAOProxy.sol'; -import { NounsDAOProxyV2 } from '../../../contracts/governance/NounsDAOProxyV2.sol'; +import { INounsDAOLogic } from '../../../contracts/interfaces/INounsDAOLogic.sol'; import { NounsDescriptorV2 } from '../../../contracts/NounsDescriptorV2.sol'; import { DeployUtilsFork } from './DeployUtilsFork.sol'; import { NounsToken } from '../../../contracts/NounsToken.sol'; @@ -15,8 +12,12 @@ import { NounsDAOExecutor } from '../../../contracts/governance/NounsDAOExecutor import { INounsTokenForkLike } from '../../../contracts/governance/fork/newdao/governance/INounsTokenForkLike.sol'; import { Utils } from './Utils.sol'; +interface DAOLogicFork { + function _setQuorumVotesBPS(uint256 newQuorumVotesBPS) external; +} + abstract contract NounsDAOLogicSharedBaseTest is Test, DeployUtilsFork { - INounsDAOShared daoProxy; + INounsDAOLogic daoProxy; NounsToken nounsToken; NounsDAOExecutor timelock = new NounsDAOExecutor(address(1), TIMELOCK_DELAY); address vetoer = address(0x3); @@ -47,7 +48,7 @@ abstract contract NounsDAOLogicSharedBaseTest is Test, DeployUtilsFork { address timelock, address nounsToken, address vetoer - ) internal virtual returns (INounsDAOShared); + ) internal virtual returns (INounsDAOLogic); function daoVersion() internal virtual returns (uint256) { return 0; // override to specify version @@ -99,36 +100,28 @@ abstract contract NounsDAOLogicSharedBaseTest is Test, DeployUtilsFork { vm.roll(block.number + daoProxy.votingDelay() + daoProxy.votingPeriod() + 1); } - function vote( - address voter, - uint256 proposalId, - uint8 support - ) internal { + function vote(address voter, uint256 proposalId, uint8 support) internal { vm.prank(voter); daoProxy.castVote(proposalId, support); } - function daoProxyAsV2() internal view returns (NounsDAOLogicV2) { - return NounsDAOLogicV2(payable(address(daoProxy))); - } - - function deployForkDAOProxy() internal returns (INounsDAOShared) { + function deployForkDAOProxy() internal returns (INounsDAOLogic) { (address treasuryAddress, address tokenAddress, address daoAddress) = _deployForkDAO(); timelock = NounsDAOExecutor(payable(treasuryAddress)); nounsToken = NounsToken(tokenAddress); minter = nounsToken.minter(); - INounsDAOShared dao = INounsDAOShared(daoAddress); + INounsDAOLogic dao = INounsDAOLogic(daoAddress); - vm.startPrank(dao.timelock()); + vm.startPrank(address(dao.timelock())); dao._setVotingPeriod(votingPeriod); dao._setVotingDelay(votingDelay); dao._setProposalThresholdBPS(proposalThresholdBPS); - dao._setQuorumVotesBPS(1000); + DAOLogicFork(address(dao))._setQuorumVotesBPS(1000); vm.stopPrank(); vm.warp(INounsTokenForkLike(tokenAddress).forkingPeriodEndTimestamp()); - return INounsDAOShared(daoAddress); + return INounsDAOLogic(daoAddress); } } diff --git a/packages/nouns-contracts/test/foundry/helpers/SigUtils.sol b/packages/nouns-contracts/test/foundry/helpers/SigUtils.sol index 68111f0bc0..a0120d3fa2 100644 --- a/packages/nouns-contracts/test/foundry/helpers/SigUtils.sol +++ b/packages/nouns-contracts/test/foundry/helpers/SigUtils.sol @@ -4,8 +4,8 @@ pragma solidity ^0.8.15; import 'forge-std/Test.sol'; import { ECDSA } from '@openzeppelin/contracts/utils/cryptography/ECDSA.sol'; import { IERC1271 } from '@openzeppelin/contracts/interfaces/IERC1271.sol'; -import { NounsDAOStorageV3 } from '../../../contracts/governance/NounsDAOInterfaces.sol'; -import { NounsDAOV3Proposals } from '../../../contracts/governance/NounsDAOV3Proposals.sol'; +import { NounsDAOTypes } from '../../../contracts/governance/NounsDAOInterfaces.sol'; +import { NounsDAOProposals } from '../../../contracts/governance/NounsDAOProposals.sol'; contract SigUtils is Test { bytes32 public constant DOMAIN_TYPEHASH = @@ -25,7 +25,7 @@ contract SigUtils is Test { struct UpdateProposalParams { uint256 proposalId; address proposer; - NounsDAOV3Proposals.ProposalTxs txs; + NounsDAOProposals.ProposalTxs txs; string description; } @@ -35,7 +35,7 @@ contract SigUtils is Test { uint256[] memory expirationTimestamps, UpdateProposalParams memory proposalParams, address verifyingContract - ) internal returns (NounsDAOStorageV3.ProposerSignature[] memory sigs) { + ) internal view returns (NounsDAOTypes.ProposerSignature[] memory sigs) { return makeUpdateProposalSigs( signers, @@ -54,10 +54,10 @@ contract SigUtils is Test { UpdateProposalParams memory proposalParams, address verifyingContract, string memory domainName - ) internal returns (NounsDAOStorageV3.ProposerSignature[] memory sigs) { - sigs = new NounsDAOStorageV3.ProposerSignature[](signers.length); + ) internal view returns (NounsDAOTypes.ProposerSignature[] memory sigs) { + sigs = new NounsDAOTypes.ProposerSignature[](signers.length); for (uint256 i = 0; i < signers.length; ++i) { - sigs[i] = NounsDAOStorageV3.ProposerSignature( + sigs[i] = NounsDAOTypes.ProposerSignature( signProposalUpdate( proposalParams.proposalId, proposalParams.proposer, @@ -78,12 +78,12 @@ contract SigUtils is Test { uint256 proposalId, address proposer, uint256 signerPK, - NounsDAOV3Proposals.ProposalTxs memory txs, + NounsDAOProposals.ProposalTxs memory txs, string memory description, uint256 expirationTimestamp, address verifyingContract, string memory domainName - ) public returns (bytes memory) { + ) public view returns (bytes memory) { return sign( abi.encodePacked(proposalId, calcProposalEncodeData(proposer, txs, description)), @@ -98,23 +98,23 @@ contract SigUtils is Test { function signProposal( address proposer, uint256 signerPK, - NounsDAOV3Proposals.ProposalTxs memory txs, + NounsDAOProposals.ProposalTxs memory txs, string memory description, uint256 expirationTimestamp, address verifyingContract - ) public returns (bytes memory) { + ) public view returns (bytes memory) { return signProposal(proposer, signerPK, txs, description, expirationTimestamp, verifyingContract, 'Nouns DAO'); } function signProposal( address proposer, uint256 signerPK, - NounsDAOV3Proposals.ProposalTxs memory txs, + NounsDAOProposals.ProposalTxs memory txs, string memory description, uint256 expirationTimestamp, address verifyingContract, string memory domainName - ) public returns (bytes memory) { + ) public view returns (bytes memory) { return sign( calcProposalEncodeData(proposer, txs, description), @@ -133,7 +133,7 @@ contract SigUtils is Test { address verifyingContract, string memory domainName, bytes32 structTypeHash - ) public returns (bytes memory) { + ) public view returns (bytes memory) { bytes32 structHash = keccak256(abi.encodePacked(structTypeHash, proposalEncodeData, expirationTimestamp)); bytes32 domainSeparator = keccak256( @@ -148,7 +148,7 @@ contract SigUtils is Test { function calcProposalEncodeData( address proposer, - NounsDAOV3Proposals.ProposalTxs memory txs, + NounsDAOProposals.ProposalTxs memory txs, string memory description ) internal pure returns (bytes memory) { bytes32[] memory signatureHashes = new bytes32[](txs.signatures.length); diff --git a/packages/nouns-contracts/test/foundry/libs/ClientRewardsMemoryMapping.t.sol b/packages/nouns-contracts/test/foundry/libs/ClientRewardsMemoryMapping.t.sol new file mode 100644 index 0000000000..437817cea2 --- /dev/null +++ b/packages/nouns-contracts/test/foundry/libs/ClientRewardsMemoryMapping.t.sol @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity ^0.8.19; + +import 'forge-std/Test.sol'; +import { ClientRewardsMemoryMapping } from '../../../contracts/libs/ClientRewardsMemoryMapping.sol'; + +contract ClientRewardsMemoryMappingTest is Test { + using ClientRewardsMemoryMapping for ClientRewardsMemoryMapping.Mapping; + + function test_set_get() public { + ClientRewardsMemoryMapping.Mapping memory m = ClientRewardsMemoryMapping.createMapping({ maxClientId: 3 }); + + m.set(0, 100); + m.set(3, 200); + assertEq(m.get(0), 100); + assertEq(m.get(3), 200); + } + + function test_inc() public { + ClientRewardsMemoryMapping.Mapping memory m = ClientRewardsMemoryMapping.createMapping({ maxClientId: 3 }); + + m.inc(0, 5); + m.inc(0, 5); + assertEq(m.get(0), 10); + + m.set(3, 200); + m.inc(3, 50); + assertEq(m.get(3), 250); + } + + function test_id_too_high() public { + ClientRewardsMemoryMapping.Mapping memory m = ClientRewardsMemoryMapping.createMapping({ maxClientId: 3 }); + + // works + m.set(3, 100); + + //fails + vm.expectRevert(); + m.set(4, 100); + } +} diff --git a/packages/nouns-contracts/test/foundry/libs/ETHString.t.sol b/packages/nouns-contracts/test/foundry/libs/ETHString.t.sol new file mode 100644 index 0000000000..28ad05b511 --- /dev/null +++ b/packages/nouns-contracts/test/foundry/libs/ETHString.t.sol @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity ^0.8.19; + +import 'forge-std/Test.sol'; +import { ETHString } from '../../../contracts/libs/ETHString.sol'; + +contract ETHStringTest is Test { + using ETHString for uint256; + + function test_toETHString_works() public { + uint256 amount = 1420000000000000000; + assertEq(amount.toETHString(), '1.42'); + + amount = 42000000000000000000; + assertEq(amount.toETHString(), '42.00'); + + amount = 4200000000000000000; + assertEq(amount.toETHString(), '4.20'); + + amount = 4020000000000000000; + assertEq(amount.toETHString(), '4.02'); + } +} diff --git a/packages/nouns-contracts/test/foundry/rewards/ProposalRewards.t.sol b/packages/nouns-contracts/test/foundry/rewards/ProposalRewards.t.sol new file mode 100644 index 0000000000..4fec95ba5f --- /dev/null +++ b/packages/nouns-contracts/test/foundry/rewards/ProposalRewards.t.sol @@ -0,0 +1,891 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity ^0.8.19; + +import { NounsDAOLogicBaseTest } from '../NounsDAOLogic/NounsDAOLogicBaseTest.sol'; +import { ERC20Mock } from '../helpers/ERC20Mock.sol'; +import { Rewards } from '../../../contracts/client-incentives/Rewards.sol'; +import { INounsAuctionHouseV2 } from '../../../contracts/interfaces/INounsAuctionHouseV2.sol'; +import { AuctionHouseUpgrader } from '../helpers/AuctionHouseUpgrader.sol'; +import { NounsAuctionHouseProxy } from '../../../contracts/proxies/NounsAuctionHouseProxy.sol'; +import { NounsToken } from '../../../contracts/NounsToken.sol'; +import { RewardsDeployer } from '../../../script/Rewards/RewardsDeployer.sol'; +import 'forge-std/Test.sol'; + +abstract contract BaseProposalRewardsTest is NounsDAOLogicBaseTest { + Rewards rewards; + ERC20Mock erc20Mock = new ERC20Mock(); + INounsAuctionHouseV2 auctionHouse; + + address admin = makeAddr('admin'); + address bidder1 = makeAddr('bidder1'); + address bidder2 = makeAddr('bidder2'); + address client1Wallet = makeAddr('client1Wallet'); + uint32 clientId1; + uint32 clientId2; + uint32[] votingClientIds; + Rewards.AuctionRewardParams auctionParams; + Rewards.ProposalRewardParams proposalParams; + + uint256 constant SECONDS_IN_BLOCK = 12; + + function setUp() public virtual override { + _setUpDAO(); + + vm.deal(bidder1, 1000 ether); + vm.deal(bidder2, 1000 ether); + + // need at least one settled auction + bidAndSettleAuction(1 ether); + bidAndSettleAuction(bidder2, 1 ether); + mineBlocks(1); + + // increase total supply to > 10 + while (nounsToken.totalSupply() < 10) { + bidAndSettleAuction({ bidAmount: 1 ether }); + } + + vm.prank(makeAddr('noundersDAO')); + nounsToken.transferFrom(makeAddr('noundersDAO'), bidder2, 0); + + rewards = RewardsDeployer.deployRewards(dao, admin, minter, address(erc20Mock), address(0)); + + vm.prank(address(dao.timelock())); + rewards.setProposalRewardParams( + Rewards.ProposalRewardParams({ + minimumRewardPeriod: 2 weeks, + numProposalsEnoughForReward: 30, + proposalRewardBps: 100, + votingRewardBps: 50, + proposalEligibilityQuorumBps: 1000 + }) + ); + + vm.prank(address(dao.timelock())); + rewards.enableProposalRewards(); + + vm.prank(client1Wallet); + clientId1 = rewards.registerClient('client1', 'client1 description'); + clientId2 = rewards.registerClient('client2', 'client2 description'); + + erc20Mock.mint(address(rewards), 100 ether); + + vm.prank(rewards.owner()); + rewards.setClientApproval(clientId1, true); + } + + function _setUpDAO() internal { + dao = _deployDAOV3WithParams({ auctionDuration: 24 hours }); + nounsToken = NounsToken(address(dao.nouns())); + minter = nounsToken.minter(); + + auctionHouse = INounsAuctionHouseV2(minter); + vm.prank(address(dao.timelock())); + auctionHouse.unpause(); + + AuctionHouseUpgrader.upgradeAuctionHouse( + address(dao.timelock()), + auctionHouseProxyAdmin, + NounsAuctionHouseProxy(payable(address(auctionHouse))) + ); + } + + function proposeVoteAndEndVotingPeriod(uint32 clientId) internal returns (uint32) { + uint32 proposalId = proposeAndVote(clientId); + mineBlocks(VOTING_PERIOD); + return proposalId; + } + + function proposeAndVote(uint32 clientId) internal returns (uint32) { + uint256 proposalId = propose(bidder1, address(1), 1 ether, '', '', 'my proposal', clientId); + mineBlocks(VOTING_DELAY + UPDATABLE_PERIOD_BLOCKS + 1); + vote(bidder1, proposalId, 1, 'i support'); + return uint32(proposalId); + } + + function bidAndSettleAuction(address bidder, uint256 bidAmount) internal returns (uint256) { + uint256 nounId = auctionHouse.auction().nounId; + + vm.prank(bidder); + auctionHouse.createBid{ value: bidAmount }(nounId); + + return fastforwardAndSettleAuction(); + } + + function bidAndSettleAuction(uint256 bidAmount) internal returns (uint256) { + return bidAndSettleAuction(bidder1, bidAmount); + } + + function fastforwardAndSettleAuction() internal returns (uint256) { + uint256 nounId = auctionHouse.auction().nounId; + + uint256 blocksToEnd = (auctionHouse.auction().endTime - block.timestamp) / SECONDS_IN_BLOCK + 1; + mineBlocks(blocksToEnd); + auctionHouse.settleCurrentAndCreateNewAuction(); + + return nounId; + } + + function settleAuction() internal returns (uint256 settledNounId) { + settledNounId = auctionHouse.auction().nounId; + auctionHouse.settleCurrentAndCreateNewAuction(); + } + + function mineBlocks(uint256 numBlocks) internal { + vm.roll(block.number + numBlocks); + vm.warp(block.timestamp + numBlocks * SECONDS_IN_BLOCK); + } + + function vote(address voter_, uint256 proposalId_, uint8 support, string memory reason) internal { + vm.prank(voter_); + dao.castRefundableVoteWithReason(proposalId_, support, reason); + } + + function vote(address voter_, uint256 proposalId_, uint8 support, string memory reason, uint32 clientId) internal { + vm.prank(voter_); + dao.castRefundableVoteWithReason(proposalId_, support, reason, clientId); + } +} + +contract DisablingTest is BaseProposalRewardsTest { + function test_rewardsAreDisabledByDefault() public { + rewards = RewardsDeployer.deployRewards(dao, admin, minter, address(erc20Mock), address(0)); + assertFalse(rewards.proposalRewardsEnabled()); + } + + function test_disableRewards_revertsForNonOwner() public { + vm.prank(makeAddr('rando')); + vm.expectRevert('Ownable: caller is not the owner'); + rewards.disableProposalRewards(); + } + + function test_disableRewards_worksForOwner() public { + vm.prank(rewards.owner()); + rewards.disableProposalRewards(); + + assertFalse(rewards.proposalRewardsEnabled()); + } +} + +contract DisabledTest is BaseProposalRewardsTest { + function setUp() public override { + super.setUp(); + vm.prank(rewards.owner()); + rewards.disableProposalRewards(); + } + + function test_updateRewardsReverts() public { + vm.expectRevert(Rewards.RewardsDisabled.selector); + rewards.updateRewardsForProposalWritingAndVoting(5, votingClientIds); + } +} + +contract ProposalRewardsTest is BaseProposalRewardsTest { + function test_revertsIfNoAuctionRevenue() public { + fastforwardAndSettleAuction(); + fastforwardAndSettleAuction(); + + vm.warp(block.timestamp + 2 weeks + 1); + uint32 proposalId = proposeVoteAndEndVotingPeriod(clientId1); + + settleAuction(); + votingClientIds = [0]; + vm.expectRevert('auctionRevenue must be > 0'); + rewards.updateRewardsForProposalWritingAndVoting({ + lastProposalId: proposalId, + votingClientIds: votingClientIds + }); + } + + function test_revertsIfProposalsNotDoneWithVoting() public { + bidAndSettleAuction({ bidAmount: 5 ether }); + + vm.warp(block.timestamp + 2 weeks + 1); + uint32 proposalId = proposeAndVote(clientId1); + + settleAuction(); + votingClientIds = [0]; + vm.expectRevert('all proposals must be done with voting'); + rewards.updateRewardsForProposalWritingAndVoting({ + lastProposalId: proposalId, + votingClientIds: votingClientIds + }); + } + + function test_revertsIfProposalWithNoVotesYetIsNotDoneWithVoting() public { + bidAndSettleAuction({ bidAmount: 5 ether }); + + vm.warp(block.timestamp + 2 weeks + 1); + proposeVoteAndEndVotingPeriod(clientId1); + uint256 proposalId2 = propose(bidder1, address(1), 1 ether, '', '', 'my proposal', clientId1); + + settleAuction(); + votingClientIds = [0]; + vm.expectRevert('all proposals must be done with voting'); + rewards.updateRewardsForProposalWritingAndVoting({ + lastProposalId: uint32(proposalId2), + votingClientIds: votingClientIds + }); + } + + function test_rewardsAfterMinimumRewardPeriod() public { + uint256 startTimestamp = block.timestamp; + + bidAndSettleAuction({ bidAmount: 5 ether }); + bidAndSettleAuction({ bidAmount: 10 ether }); + + vm.warp(startTimestamp + 2 weeks + 1); + uint32 proposalId = proposeVoteAndEndVotingPeriod(clientId1); + + settleAuction(); + votingClientIds = [0]; + rewards.updateRewardsForProposalWritingAndVoting({ + lastProposalId: proposalId, + votingClientIds: votingClientIds + }); + + assertEq(rewards.clientBalance(clientId1), 0.15 ether); // 15 eth * 1% + } + + function test_refundsGas() public { + uint256 startTimestamp = block.timestamp; + + bidAndSettleAuction({ bidAmount: 5 ether }); + bidAndSettleAuction({ bidAmount: 10 ether }); + + vm.warp(startTimestamp + 2 weeks + 1); + uint32 proposalId = proposeVoteAndEndVotingPeriod(clientId1); + + settleAuction(); + votingClientIds = [0]; + + uint256 startGas = gasleft(); + vm.fee(100 gwei); + vm.txGasPrice(100 gwei); + vm.prank(makeAddr('caller'), makeAddr('caller tx.origin')); + rewards.updateRewardsForProposalWritingAndVoting({ + lastProposalId: proposalId, + votingClientIds: votingClientIds + }); + uint256 gasUsed = startGas - gasleft(); + uint256 approxEthRefunded = (gasUsed + 36000) * 100 gwei; + + assertApproxEqAbs(erc20Mock.balanceOf(makeAddr('caller tx.origin')), approxEthRefunded, 0.01 ether); + } + + function test_allVotingClientIdsMustHaveVotes() public { + uint256 startTimestamp = block.timestamp; + + bidAndSettleAuction({ bidAmount: 5 ether }); + bidAndSettleAuction({ bidAmount: 10 ether }); + + vm.warp(startTimestamp + 2 weeks + 1); + uint32 proposalId = proposeVoteAndEndVotingPeriod(clientId1); + + settleAuction(); + votingClientIds = [0, 2]; + vm.expectRevert('all clientId must have votes'); + rewards.updateRewardsForProposalWritingAndVoting({ + lastProposalId: proposalId, + votingClientIds: votingClientIds + }); + } + + function test_votingClientIdsMustBeSorted() public { + uint32 proposalId = proposeVoteAndEndVotingPeriod(clientId1); + + votingClientIds = [0, 5, 4]; + vm.expectRevert('must be sorted & unique'); + rewards.updateRewardsForProposalWritingAndVoting({ + lastProposalId: proposalId, + votingClientIds: votingClientIds + }); + } + + function test_votingClientIdsMustBeUnique() public { + uint32 proposalId = proposeVoteAndEndVotingPeriod(clientId1); + + votingClientIds = [0, 0]; + vm.expectRevert('must be sorted & unique'); + rewards.updateRewardsForProposalWritingAndVoting({ + lastProposalId: proposalId, + votingClientIds: votingClientIds + }); + + votingClientIds = [0, 1, 0]; + vm.expectRevert('must be sorted & unique'); + rewards.updateRewardsForProposalWritingAndVoting({ + lastProposalId: proposalId, + votingClientIds: votingClientIds + }); + } + + function test_doesntRewardIneligibleProposals() public { + uint256 startTimestamp = block.timestamp; + + bidAndSettleAuction({ bidAmount: 5 ether }); + bidAndSettleAuction({ bidAmount: 10 ether }); + + vm.warp(startTimestamp + 2 weeks + 1); + propose(bidder2, address(1), 1 ether, '', '', 'my proposal', clientId1); + uint32 proposalId = proposeVoteAndEndVotingPeriod(clientId2); + + settleAuction(); + votingClientIds = [0]; + rewards.updateRewardsForProposalWritingAndVoting({ + lastProposalId: proposalId, + votingClientIds: votingClientIds + }); + + assertEq(rewards.clientBalance(clientId1), 0 ether); + assertEq(rewards.clientBalance(clientId2), 0.15 ether); // 15 eth * 1% + } + + function test_onlyEligibleProposalsCanSetTheRewardsPeriod() public { + uint256 startTimestamp = block.timestamp; + + bidAndSettleAuction({ bidAmount: 5 ether }); + bidAndSettleAuction({ bidAmount: 10 ether }); + + vm.warp(startTimestamp + 2 weeks + 1); + proposeVoteAndEndVotingPeriod(clientId2); + + settleAuction(); + bidAndSettleAuction({ bidAmount: 100 ether }); + + // trying to create a bogus proposal to capture the high auction as reward + uint32 proposalId = uint32(propose(bidder2, address(1), 1 ether, '', '', 'my proposal', 0)); + mineBlocks(VOTING_DELAY + UPDATABLE_PERIOD_BLOCKS + VOTING_PERIOD + 1); + + votingClientIds = [0]; + rewards.updateRewardsForProposalWritingAndVoting({ + lastProposalId: proposalId, + votingClientIds: votingClientIds + }); + + assertEq(rewards.clientBalance(clientId2), 0.15 ether); // 15 eth * 1% + } + + function test_cantUseIneligibleProposalToPassTheMinimumPeriod() public { + // The state in this test: + // Number of eligible proposals < `numProposalsEnoughForReward` + // The last proposal is after `minimumRewardPeriod`, but it's not eligible, so it shouldn't + // be considered when looking at how much time passed. + uint256 startTimestamp = block.timestamp; + + bidAndSettleAuction({ bidAmount: 5 ether }); + bidAndSettleAuction({ bidAmount: 10 ether }); + + proposeVoteAndEndVotingPeriod(clientId2); + + vm.warp(startTimestamp + 2 weeks + 1); + + // bogus proposal no one will vote on + uint32 proposalId = uint32(propose(bidder2, address(1), 1 ether, '', '', 'my proposal', 0)); + mineBlocks(VOTING_DELAY + UPDATABLE_PERIOD_BLOCKS + VOTING_PERIOD + 1); + + votingClientIds = [0]; + vm.expectRevert('not enough time passed'); + rewards.updateRewardsForProposalWritingAndVoting({ + lastProposalId: proposalId, + votingClientIds: votingClientIds + }); + } + + function test_splitsRewardsBetweenEligibleProposals() public { + uint256 firstAuctionId = rewards.nextProposalRewardFirstAuctionId(); + uint256 startTimestamp = block.timestamp; + + bidAndSettleAuction({ bidAmount: 5 ether }); + uint256 lastAuctionId = bidAndSettleAuction({ bidAmount: 10 ether }); + + vm.warp(startTimestamp + 2 weeks + 1); + proposeVoteAndEndVotingPeriod(clientId1); + uint32 proposalId = proposeVoteAndEndVotingPeriod(clientId2); + + settleAuction(); + votingClientIds = [0]; + + vm.expectEmit(); + emit Rewards.ProposalRewardsUpdated( + 1, + 2, + firstAuctionId, + lastAuctionId, + 15 ether, + 0.075 ether, + 4166666666666666 + ); + rewards.updateRewardsForProposalWritingAndVoting({ + lastProposalId: proposalId, + votingClientIds: votingClientIds + }); + + assertEq(rewards.clientBalance(clientId1), 0.075 ether); // 15 eth * 1% / 2 + assertEq(rewards.clientBalance(clientId2), 0.075 ether); // 15 eth * 1% / 2 + } + + function test_givenClientIdAboveTotalSupply_skipsIt() public { + uint256 firstAuctionId = rewards.nextProposalRewardFirstAuctionId(); + uint256 startTimestamp = block.timestamp; + uint32 badClientId = rewards.nextTokenId(); + + bidAndSettleAuction({ bidAmount: 5 ether }); + uint256 lastAuctionId = bidAndSettleAuction({ bidAmount: 10 ether }); + + vm.warp(startTimestamp + 2 weeks + 1); + proposeVoteAndEndVotingPeriod(clientId1); + uint32 proposalId = proposeVoteAndEndVotingPeriod(badClientId); + + settleAuction(); + votingClientIds = [0]; + + vm.expectEmit(); + emit Rewards.ProposalRewardsUpdated( + 1, + 2, + firstAuctionId, + lastAuctionId, + 15 ether, + 0.075 ether, + 4166666666666666 + ); + rewards.updateRewardsForProposalWritingAndVoting({ + lastProposalId: proposalId, + votingClientIds: votingClientIds + }); + + assertEq(rewards.clientBalance(clientId1), 0.075 ether); // 15 eth * 1% / 2 + } + + function test_doesntRewardIfMinimumPeriodHasntPassed() public { + uint256 startTimestamp = block.timestamp; + + bidAndSettleAuction({ bidAmount: 5 ether }); + bidAndSettleAuction({ bidAmount: 10 ether }); + + vm.warp(startTimestamp + 2 weeks - 10); + + uint32 proposalId = proposeVoteAndEndVotingPeriod(clientId1); + + settleAuction(); + + votingClientIds = [0]; + vm.expectRevert('not enough time passed'); + rewards.updateRewardsForProposalWritingAndVoting({ + lastProposalId: proposalId, + votingClientIds: votingClientIds + }); + } + + function test_rewardsIfMinimumNumberOfProposalsWereCreated_evenIfMinimumPeriodHasntPassed() public { + // set numProposalsEnoughForReward to 1 + vm.prank(address(dao.timelock())); + rewards.setProposalRewardParams( + Rewards.ProposalRewardParams({ + minimumRewardPeriod: 2 weeks, + numProposalsEnoughForReward: 1, + proposalRewardBps: 100, + votingRewardBps: 50, + proposalEligibilityQuorumBps: 1000 + }) + ); + + uint256 startTimestamp = block.timestamp; + + bidAndSettleAuction({ bidAmount: 5 ether }); + bidAndSettleAuction({ bidAmount: 10 ether }); + + vm.warp(startTimestamp + 2 weeks - 10); + + uint32 proposalId = proposeVoteAndEndVotingPeriod(clientId1); + + settleAuction(); + + votingClientIds = [0]; + rewards.updateRewardsForProposalWritingAndVoting({ + lastProposalId: proposalId, + votingClientIds: votingClientIds + }); + assertEq(rewards.clientBalance(clientId1), 0.15 ether); // 15 eth * 1% + } +} + +contract ProposalRewardsEligibilityTest is BaseProposalRewardsTest { + uint256 lastNounId; + uint32 proposalId; + + function setUp() public virtual override { + super.setUp(); + + uint256 startTimestamp = block.timestamp; + bidAndSettleAuction({ bidAmount: 5 ether }); + vm.warp(startTimestamp + 2 weeks + 1); + proposalId = proposeVoteAndEndVotingPeriod(clientId1); + + lastNounId = settleAuction(); + + // verify assumptions + assertEq(nounsToken.totalSupply(), 12); + assertEq(nounsToken.getCurrentVotes(bidder1), 8); + + votingClientIds = [0]; + } + + function test_ineligibleIfBelowQuorum() public { + // set quorum to >= 75% so that quorum requires 9 votes + proposalParams.proposalEligibilityQuorumBps = 7500; + vm.prank(address(dao.timelock())); + rewards.setProposalRewardParams(proposalParams); + + vm.expectRevert('at least one eligible proposal'); + rewards.updateRewardsForProposalWritingAndVoting({ + lastProposalId: proposalId, + votingClientIds: votingClientIds + }); + } + + function test_eligibleIfAboveQuorum() public { + proposalParams.proposalEligibilityQuorumBps = 7000; // (12 * 7000 / 10000) = 8 + vm.prank(address(dao.timelock())); + rewards.setProposalRewardParams(proposalParams); + + rewards.updateRewardsForProposalWritingAndVoting({ + lastProposalId: proposalId, + votingClientIds: votingClientIds + }); + } + + function test_canceledProposalsAreIneligible() public { + proposalParams.proposalEligibilityQuorumBps = 7000; // (12 * 7000 / 10000) = 8 + vm.prank(address(dao.timelock())); + rewards.setProposalRewardParams(proposalParams); + + vm.prank(bidder1); + dao.cancel(proposalId); + + vm.expectRevert('at least one eligible proposal'); + rewards.updateRewardsForProposalWritingAndVoting({ + lastProposalId: proposalId, + votingClientIds: votingClientIds + }); + } +} + +contract AfterOneSuccessfulRewardsDistributionTest is BaseProposalRewardsTest { + uint256 lastProposalCreationTimestamp; + + function setUp() public virtual override { + super.setUp(); + + uint256 startTimestamp = block.timestamp; + + bidAndSettleAuction({ bidAmount: 10 ether }); + + vm.warp(startTimestamp + 2 weeks + 1); + lastProposalCreationTimestamp = block.timestamp; + uint32 proposalId = proposeVoteAndEndVotingPeriod(clientId1); + + settleAuction(); + votingClientIds = [0]; + rewards.updateRewardsForProposalWritingAndVoting({ + lastProposalId: proposalId, + votingClientIds: votingClientIds + }); + + assertEq(rewards.clientBalance(clientId1), 0.1 ether); // 10 eth * 1% + } + + function test_revertsIfMinimumPeriodHasntPassedAgain() public { + bidAndSettleAuction({ bidAmount: 5 ether }); + + vm.warp(lastProposalCreationTimestamp + 2 weeks - 10); + uint32 proposalId = proposeVoteAndEndVotingPeriod(clientId1); + + settleAuction(); + vm.expectRevert('not enough time passed'); + rewards.updateRewardsForProposalWritingAndVoting({ + lastProposalId: proposalId, + votingClientIds: votingClientIds + }); + } + + function test_rewardsIfMinimumPeriodPassedAgain() public { + bidAndSettleAuction({ bidAmount: 5 ether }); + + vm.warp(lastProposalCreationTimestamp + 2 weeks + 10); + uint32 proposalId = proposeVoteAndEndVotingPeriod(clientId1); + + settleAuction(); + rewards.updateRewardsForProposalWritingAndVoting({ + lastProposalId: proposalId, + votingClientIds: votingClientIds + }); + + assertEq(rewards.clientBalance(clientId1), 0.15 ether); + } + + function test_clientCanWithdrawBalance() public { + vm.prank(client1Wallet); + vm.expectEmit(); + emit Rewards.ClientBalanceWithdrawal(clientId1, 0.05 ether, client1Wallet); + rewards.withdrawClientBalance(clientId1, client1Wallet, 0.05 ether); + + assertEq(erc20Mock.balanceOf(client1Wallet), 0.05 ether); + } + + function test_withdrawingMoreThanBalanceReverts() public { + uint96 balance = rewards.clientBalance(clientId1); + vm.prank(client1Wallet); + vm.expectRevert('amount too large'); + rewards.withdrawClientBalance(clientId1, client1Wallet, balance + 1); + } + + function test_withdrawingUpdatesBalance() public { + uint96 balance = rewards.clientBalance(clientId1); + + vm.prank(client1Wallet); + rewards.withdrawClientBalance(clientId1, client1Wallet, balance); + + vm.prank(client1Wallet); + vm.expectRevert('amount too large'); + rewards.withdrawClientBalance(clientId1, client1Wallet, 1); + } + + function test_withdraw_revertsIfNotClientIdOwner() public { + vm.expectRevert(Rewards.OnlyNFTOwner.selector); + rewards.withdrawClientBalance(clientId1, client1Wallet, 1); + } +} + +contract VotesRewardsTest is BaseProposalRewardsTest { + uint32 proposalId; + uint32[] expectedClientIds; + + function setUp() public virtual override { + super.setUp(); + + uint256 startTimestamp = block.timestamp; + bidAndSettleAuction({ bidAmount: 15 ether }); + vm.warp(startTimestamp + 2 weeks + 1); + + proposalId = uint32(propose(bidder1, address(1), 1 ether, '', '', 'my proposal', 0)); + mineBlocks(VOTING_DELAY + UPDATABLE_PERIOD_BLOCKS + 1); + } + + function test_singleClientVotingGetsAllTheRewards() public { + vote(bidder1, proposalId, 1, 'i support', clientId1); + mineBlocks(VOTING_PERIOD); + + settleAuction(); + votingClientIds = [clientId1]; + rewards.updateRewardsForProposalWritingAndVoting({ + lastProposalId: proposalId, + votingClientIds: votingClientIds + }); + + assertEq(rewards.clientBalance(clientId1), 0.075 ether); // 15 eth * 0.5% + } + + function test_rewardSplitBetweenTwoClients() public { + // cast 8 votes + assertEq(nounsToken.getCurrentVotes(bidder1), 8); + vote(bidder1, proposalId, 1, 'i support', clientId1); + + // cast 1 votes + assertEq(nounsToken.getCurrentVotes(bidder2), 2); + vote(bidder2, proposalId, 1, 'i support', clientId2); + + mineBlocks(VOTING_PERIOD); + + settleAuction(); + votingClientIds = [clientId1, clientId2]; + vm.expectEmit(); + emit Rewards.ClientRewarded(clientId1, 0.06 ether); + vm.expectEmit(); + emit Rewards.ClientRewarded(clientId2, 0.015 ether); + rewards.updateRewardsForProposalWritingAndVoting({ + lastProposalId: proposalId, + votingClientIds: votingClientIds + }); + + assertEq(rewards.clientBalance(clientId1), 0.06 ether); // 15 eth * 0.5% * (8/10) + assertEq(rewards.clientBalance(clientId2), 0.015 ether); // 15 eth * 0.5% * (2/10) + } + + function test_givenAnInvalidClientId_skipsIt() public { + uint32 badClientId = rewards.nextTokenId(); + + // cast 8 votes + assertEq(nounsToken.getCurrentVotes(bidder1), 8); + vote(bidder1, proposalId, 1, 'i support', clientId1); + + // cast 1 votes + assertEq(nounsToken.getCurrentVotes(bidder2), 2); + vote(bidder2, proposalId, 1, 'i support', clientId2); + + uint32 proposalId2 = uint32(propose(bidder2, address(1), 1 ether, '', '', 'my proposal', 0)); + mineBlocks(VOTING_DELAY + UPDATABLE_PERIOD_BLOCKS + 1); + vote(bidder1, proposalId2, 1, 'i support', badClientId); + vote(bidder2, proposalId2, 1, 'i support', badClientId); + + mineBlocks(VOTING_PERIOD); + + settleAuction(); + votingClientIds = [clientId1, clientId2, badClientId]; + vm.expectEmit(); + emit Rewards.ClientRewarded(clientId1, 0.03 ether); + vm.expectEmit(); + emit Rewards.ClientRewarded(clientId2, 0.0075 ether); + rewards.updateRewardsForProposalWritingAndVoting({ + lastProposalId: proposalId2, + votingClientIds: votingClientIds + }); + + assertEq(rewards.clientBalance(clientId1), 0.03 ether); // 15 eth * 0.5% * (8/20) + assertEq(rewards.clientBalance(clientId2), 0.0075 ether); // 15 eth * 0.5% * (2/20) + } + + function test_givenAProposalWhereNotAllClientContributed_updateRewardsWorks() public { + // cast 8 votes + assertEq(nounsToken.getCurrentVotes(bidder1), 8); + vote(bidder1, proposalId, 1, 'i support', clientId1); + + // cast 1 votes + assertEq(nounsToken.getCurrentVotes(bidder2), 2); + vote(bidder2, proposalId, 1, 'i support', clientId2); + + uint32 proposalId2 = uint32(propose(bidder2, address(1), 1 ether, '', '', 'my proposal', 0)); + mineBlocks(VOTING_DELAY + UPDATABLE_PERIOD_BLOCKS + 1); + vote(bidder1, proposalId2, 1, 'i support', clientId1); + vote(bidder2, proposalId2, 1, 'i support', clientId1); + + mineBlocks(VOTING_PERIOD); + + settleAuction(); + votingClientIds = [clientId1, clientId2]; + vm.expectEmit(); + emit Rewards.ClientRewarded(clientId1, 0.0675 ether); + vm.expectEmit(); + emit Rewards.ClientRewarded(clientId2, 0.0075 ether); + rewards.updateRewardsForProposalWritingAndVoting({ + lastProposalId: proposalId2, + votingClientIds: votingClientIds + }); + + assertEq(rewards.clientBalance(clientId1), 0.0675 ether); // 15 eth * 0.5% * (18/20) + assertEq(rewards.clientBalance(clientId2), 0.0075 ether); // 15 eth * 0.5% * (2/20) + } + + function test_revertsIfNotAllVotesAreAccounted() public { + vote(bidder1, proposalId, 1, 'i support', clientId1); + vote(bidder2, proposalId, 1, 'i support', clientId2); + // vote with no clientId means clientId == 0 + vote(makeAddr('noundersDAO'), proposalId, 0, 'against'); + + mineBlocks(VOTING_PERIOD); + + votingClientIds = [clientId1, clientId2]; + vm.expectRevert('not all votes accounted'); + rewards.updateRewardsForProposalWritingAndVoting({ + lastProposalId: proposalId, + votingClientIds: votingClientIds + }); + + votingClientIds = [0, clientId2]; + vm.expectRevert('not all votes accounted'); + rewards.updateRewardsForProposalWritingAndVoting({ + lastProposalId: proposalId, + votingClientIds: votingClientIds + }); + + votingClientIds = [0, clientId1, clientId2]; + rewards.updateRewardsForProposalWritingAndVoting({ + lastProposalId: proposalId, + votingClientIds: votingClientIds + }); + } + + function test_getVotingClientIds() public { + vote(bidder1, proposalId, 1, 'i support', clientId1); + expectedClientIds = [1]; + mineBlocks(VOTING_PERIOD); + assertEq(rewards.getVotingClientIds(proposalId), expectedClientIds); + } + + function test_getVotingClientIds2() public { + vote(bidder1, proposalId, 1, 'i support', clientId1); + vote(bidder2, proposalId, 1, 'i support', clientId2); + mineBlocks(VOTING_PERIOD); + expectedClientIds = [1, 2]; + assertEq(rewards.getVotingClientIds(proposalId), expectedClientIds); + } + + function test_getVotingClientIds3() public { + vote(bidder1, proposalId, 1, 'i support', clientId1); + vote(bidder2, proposalId, 1, 'i support', clientId2); + vote(makeAddr('noundersDAO'), proposalId, 0, 'against'); + mineBlocks(VOTING_PERIOD); + expectedClientIds = [0, 1, 2]; + assertEq(rewards.getVotingClientIds(proposalId), expectedClientIds); + } + + function test_getVotingClientIds_filtersProposalsBelowEligibilityQuorum() public { + // clientId1 should not be included because proposal only had against votes + vote(bidder1, proposalId, 0, 'against', clientId1); + mineBlocks(VOTING_PERIOD); + + uint32 proposalId2 = uint32(propose(bidder1, address(1), 1 ether, '', '', 'my proposal', 0)); + mineBlocks(VOTING_DELAY + UPDATABLE_PERIOD_BLOCKS + 1); + vote(bidder1, proposalId2, 1, 'i support', clientId2); + mineBlocks(VOTING_PERIOD); + uint32[] memory votingClientIds = rewards.getVotingClientIds(proposalId2); + + // doesn't revert. if votingClientIds included clientId1 then it would revert because the first proposal is + // ineligible, so clientId1 has zero votes + rewards.updateRewardsForProposalWritingAndVoting({ + lastProposalId: proposalId2, + votingClientIds: votingClientIds + }); + + expectedClientIds = [clientId2]; + assertEq(votingClientIds, expectedClientIds); + } + + function test_getVotingClientIds_filtersCanceledProposals() public { + // clientId1 should not be included because proposal was canceled + vote(bidder1, proposalId, 1, 'for', clientId1); + mineBlocks(VOTING_PERIOD); + + vm.prank(bidder1); + dao.cancel(proposalId); + + uint32 proposalId2 = uint32(propose(bidder1, address(1), 1 ether, '', '', 'my proposal', 0)); + mineBlocks(VOTING_DELAY + UPDATABLE_PERIOD_BLOCKS + 1); + vote(bidder1, proposalId2, 1, 'i support', clientId2); + mineBlocks(VOTING_PERIOD); + uint32[] memory votingClientIds = rewards.getVotingClientIds(proposalId2); + + // doesn't revert + rewards.updateRewardsForProposalWritingAndVoting({ + lastProposalId: proposalId2, + votingClientIds: votingClientIds + }); + + expectedClientIds = [clientId2]; + assertEq(votingClientIds, expectedClientIds); + } + + function assertEq(uint32[] memory a, uint32[] memory b) internal { + if (keccak256(abi.encode(a)) != keccak256(abi.encode(b))) { + console.log('>>> a:'); + for (uint i; i < a.length; i++) { + console.log(a[i]); + } + console.log('>>> b:'); + for (uint i; i < b.length; i++) { + console.log(b[i]); + } + fail('Array no equal'); + } + } +} diff --git a/packages/nouns-contracts/test/foundry/rewards/Rewards.t.sol b/packages/nouns-contracts/test/foundry/rewards/Rewards.t.sol new file mode 100644 index 0000000000..6784fdb023 --- /dev/null +++ b/packages/nouns-contracts/test/foundry/rewards/Rewards.t.sol @@ -0,0 +1,591 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity ^0.8.19; + +import { NounsDAOLogicBaseTest } from '../NounsDAOLogic/NounsDAOLogicBaseTest.sol'; +import { Rewards } from '../../../contracts/client-incentives/Rewards.sol'; +import { NounsToken } from '../../../contracts/NounsToken.sol'; +import { INounsAuctionHouseV2 } from '../../../contracts/interfaces/INounsAuctionHouseV2.sol'; +import { AuctionHouseUpgrader } from '../helpers/AuctionHouseUpgrader.sol'; +import { NounsAuctionHouseProxy } from '../../../contracts/proxies/NounsAuctionHouseProxy.sol'; +import { ERC20Mock } from '../helpers/ERC20Mock.sol'; +import { RewardsDeployer } from '../../../script/Rewards/RewardsDeployer.sol'; +import { INounsClientTokenTypes } from '../../../contracts/client-incentives/INounsClientTokenTypes.sol'; +import { console } from 'forge-std/console.sol'; + +abstract contract RewardsBaseTest is NounsDAOLogicBaseTest { + Rewards rewards; + INounsAuctionHouseV2 auctionHouse; + + address admin = makeAddr('admin'); + address client1Wallet = makeAddr('client1Wallet'); + address clientWallet = makeAddr('clientWallet'); + address clientWallet2 = makeAddr('clientWallet2'); + address voter = makeAddr('voter'); + address voter2 = makeAddr('voter2'); + address voter3 = makeAddr('voter3'); + address bidder1 = makeAddr('bidder1'); + address bidder2 = makeAddr('bidder2'); + + ERC20Mock erc20Mock = new ERC20Mock(); + + uint32 CLIENT_ID; + uint32 CLIENT_ID2; + + uint256 constant SECONDS_IN_BLOCK = 12; + + uint32[] clientIds; + + function setUp() public virtual override { + dao = _deployDAOV3WithParams(24 hours); + nounsToken = NounsToken(address(dao.nouns())); + minter = nounsToken.minter(); + + auctionHouse = INounsAuctionHouseV2(minter); + vm.prank(address(dao.timelock())); + auctionHouse.unpause(); + + rewards = RewardsDeployer.deployRewards(dao, admin, minter, address(erc20Mock), address(0)); + + vm.prank(address(dao.timelock())); + rewards.setAuctionRewardParams( + Rewards.AuctionRewardParams({ auctionRewardBps: 100, minimumAuctionsBetweenUpdates: 0 }) + ); + + vm.prank(address(dao.timelock())); + rewards.enableAuctionRewards(); + + vm.deal(address(rewards), 100 ether); + vm.deal(address(dao.timelock()), 100 ether); + vm.deal(bidder1, 1000 ether); + vm.deal(bidder2, 10 ether); + + for (uint256 i; i < 10; i++) { + _mintTo(voter); + _mintTo(voter2); + } + + for (uint256 i; i < 5; i++) { + _mintTo(voter3); + } + + AuctionHouseUpgrader.upgradeAuctionHouse( + address(dao.timelock()), + auctionHouseProxyAdmin, + NounsAuctionHouseProxy(payable(address(auctionHouse))) + ); + + rewards.registerClient('some client', 'some client description'); + vm.prank(client1Wallet); + CLIENT_ID = rewards.registerClient('client1', 'client1 description'); + rewards.registerClient('some client', 'some client description'); + CLIENT_ID2 = rewards.registerClient('client2', 'client2 description'); + + erc20Mock.mint(address(rewards), 100 ether); + + vm.prank(rewards.owner()); + rewards.setClientApproval(CLIENT_ID, true); + } + + function _mintTo(address to) internal returns (uint256 tokenID) { + vm.startPrank(minter); + tokenID = nounsToken.mint(); + nounsToken.transferFrom(minter, to, tokenID); + vm.stopPrank(); + vm.roll(block.number + 1); + } + + function bidAndSettleAuction(uint256 bidAmount) internal returns (uint32) { + return bidAndSettleAuction(bidAmount, 0); + } + + function bidAndSettleAuction(uint256 bidAmount, uint32 clientId) internal returns (uint32) { + uint256 nounId = auctionHouse.auction().nounId; + + vm.prank(bidder1); + auctionHouse.createBid{ value: bidAmount }(nounId, clientId); + + uint256 blocksToEnd = (auctionHouse.auction().endTime - block.timestamp) / SECONDS_IN_BLOCK + 1; + mineBlocks(blocksToEnd); + auctionHouse.settleCurrentAndCreateNewAuction(); + + return uint32(nounId); + } + + function mineBlocks(uint256 numBlocks) internal { + vm.roll(block.number + numBlocks); + vm.warp(block.timestamp + numBlocks * SECONDS_IN_BLOCK); + } +} + +contract AuctionRewards is RewardsBaseTest { + uint32 nounId; + + function setUp() public virtual override { + super.setUp(); + + bidAndSettleAuction(1 ether, CLIENT_ID); + bidAndSettleAuction(2 ether, CLIENT_ID2); + bidAndSettleAuction(3 ether, 0); + nounId = bidAndSettleAuction(4 ether, CLIENT_ID); + } + + function test_storageLocation() public { + bytes32 expected = keccak256(abi.encode(uint256(keccak256('nouns.rewards')) - 1)) & ~bytes32(uint256(0xff)); + assertEq(rewards.RewardsStorageLocation(), expected); + } + + function test_rewardsForAuctions() public { + rewards.updateRewardsForAuctions(nounId); + + assertEq(rewards.clientBalance(CLIENT_ID), 0.05 ether); + assertEq(rewards.clientBalance(CLIENT_ID2), 0.02 ether); + + vm.prank(client1Wallet); + rewards.withdrawClientBalance(CLIENT_ID, client1Wallet, 0.05 ether); + assertEq(erc20Mock.balanceOf(client1Wallet), 0.05 ether); + assertEq(rewards.clientBalance(CLIENT_ID), 0); + } + + function test_givenAnInvalidClientId_skipsIt() public { + uint32 badClientId = rewards.nextTokenId(); + nounId = bidAndSettleAuction(1.42 ether, badClientId); + + rewards.updateRewardsForAuctions(nounId); + + assertEq(rewards.clientBalance(badClientId), 0); + assertEq(rewards.clientBalance(CLIENT_ID), 0.05 ether); + assertEq(rewards.clientBalance(CLIENT_ID2), 0.02 ether); + + vm.prank(client1Wallet); + rewards.withdrawClientBalance(CLIENT_ID, client1Wallet, 0.05 ether); + assertEq(erc20Mock.balanceOf(client1Wallet), 0.05 ether); + assertEq(rewards.clientBalance(CLIENT_ID), 0); + } + + function test_withdrawClientBalance_revertsIfClientNotApproved() public { + vm.prank(rewards.owner()); + rewards.setClientApproval(CLIENT_ID, false); + + rewards.updateRewardsForAuctions(nounId); + + assertEq(rewards.clientBalance(CLIENT_ID), 0.05 ether); + assertEq(rewards.clientBalance(CLIENT_ID2), 0.02 ether); + + vm.expectRevert('not approved'); + vm.prank(client1Wallet); + rewards.withdrawClientBalance(CLIENT_ID, client1Wallet, 0.05 ether); + } + + function test_emitsClientRewardedEvent() public { + vm.expectEmit(); + emit Rewards.ClientRewarded(CLIENT_ID, 0.05 ether); + vm.expectEmit(); + emit Rewards.ClientRewarded(CLIENT_ID2, 0.02 ether); + rewards.updateRewardsForAuctions(nounId); + } + + function test_emitsAuctionRewardsUpdatedEvent() public { + vm.expectEmit(); + emit Rewards.AuctionRewardsUpdated(1, nounId); + rewards.updateRewardsForAuctions(nounId); + } + + function test_requiresMinimumNumberOfAuctionsToPass() public { + rewards.updateRewardsForAuctions(nounId); + + Rewards.AuctionRewardParams memory params = rewards.getAuctionRewardParams(); + params.minimumAuctionsBetweenUpdates = 5; + vm.prank(address(dao.timelock())); + rewards.setAuctionRewardParams(params); + + bidAndSettleAuction(1 ether, CLIENT_ID); + bidAndSettleAuction(1 ether, CLIENT_ID); + bidAndSettleAuction(1 ether, CLIENT_ID); + nounId = bidAndSettleAuction(1 ether, CLIENT_ID); + + vm.expectRevert(Rewards.LastNounIdMustBeHigher.selector); + rewards.updateRewardsForAuctions(nounId); + + bidAndSettleAuction(1 ether, CLIENT_ID); + nounId = bidAndSettleAuction(1 ether, CLIENT_ID); + rewards.updateRewardsForAuctions(nounId); + } + + function test_revertsIfAlreadyProcessedNounId() public { + rewards.updateRewardsForAuctions(nounId); + + vm.expectRevert(Rewards.LastNounIdMustBeHigher.selector); + rewards.updateRewardsForAuctions(nounId); + } + + function test_followupCallWorksCorrectly() public { + rewards.updateRewardsForAuctions(nounId); + + assertEq(rewards.clientBalance(CLIENT_ID), 0.05 ether); + assertEq(rewards.clientBalance(CLIENT_ID2), 0.02 ether); + + bidAndSettleAuction(10 ether, CLIENT_ID); + nounId = bidAndSettleAuction(20 ether, CLIENT_ID2); + + rewards.updateRewardsForAuctions(nounId); + + assertEq(rewards.clientBalance(CLIENT_ID), 0.15 ether); + assertEq(rewards.clientBalance(CLIENT_ID2), 0.22 ether); + } + + function test_canProcessLastNounOnAuctionIfAuctionPausedAndSettled() public { + uint256 blocksToEnd = (auctionHouse.auction().endTime - block.timestamp) / SECONDS_IN_BLOCK + 1; + mineBlocks(blocksToEnd); + vm.prank(address(dao.timelock())); + auctionHouse.pause(); + auctionHouse.settleAuction(); + + rewards.updateRewardsForAuctions(nounId + 1); + } + + function test_nounIdMustBeSettled() public { + vm.expectRevert(Rewards.LastNounIdMustBeSettled.selector); + rewards.updateRewardsForAuctions(nounId + 1); + } + + function test_refundsGas() public { + for (uint256 i; i < 100; ++i) { + nounId = bidAndSettleAuction(1 ether, CLIENT_ID); + } + + uint256 startGas = gasleft(); + + vm.fee(100 gwei); + vm.txGasPrice(100 gwei); + vm.prank(makeAddr('caller'), makeAddr('caller tx.origin')); + rewards.updateRewardsForAuctions(nounId); + + uint256 gasUsed = startGas - gasleft(); + uint256 approxEthRefunded = (gasUsed + 36000) * 100 gwei; + + assertApproxEqAbs(erc20Mock.balanceOf(makeAddr('caller tx.origin')), approxEthRefunded, 0.01 ether); + } + + function test_doesntRefundGasIfOnlyZeroClientIds() public { + // reset state + rewards.updateRewardsForAuctions(nounId); + + for (uint256 i; i < 100; ++i) { + nounId = bidAndSettleAuction(1 ether, 0); + } + + vm.fee(100 gwei); + vm.txGasPrice(100 gwei); + vm.prank(makeAddr('caller'), makeAddr('caller tx.origin')); + rewards.updateRewardsForAuctions(nounId); + + assertEq(erc20Mock.balanceOf(makeAddr('caller tx.origin')), 0); + } + + function test_refundsGas_givenFailedTokenTransfer_reverts() public { + for (uint256 i; i < 100; ++i) { + nounId = bidAndSettleAuction(1 ether, CLIENT_ID); + } + + erc20Mock.setFailNextTransfer(true); + + vm.expectRevert('SafeERC20: ERC20 operation did not succeed'); + rewards.updateRewardsForAuctions(nounId); + } + + function test_withdrawClientBalance_givenFailedTokenTransfer_reverts() public { + rewards.updateRewardsForAuctions(nounId); + + erc20Mock.setFailNextTransfer(true); + + vm.prank(client1Wallet); + vm.expectRevert('SafeERC20: ERC20 operation did not succeed'); + rewards.withdrawClientBalance(CLIENT_ID, client1Wallet, 0.05 ether); + } +} + +contract RewardsUpgradeTest is RewardsBaseTest { + function test_upgrade_worksForOwner() public { + Rewards newLogic = new Rewards(address(dao), minter); + + vm.prank(rewards.owner()); + rewards.upgradeTo(address(newLogic)); + + assertEq(get1967Implementation(address(rewards)), address(newLogic)); + } + + function test_upgrade_revertsForNonOwner() public { + Rewards newLogic = new Rewards(address(dao), minter); + + vm.prank(makeAddr('nonOwner')); + vm.expectRevert('Ownable: caller is not the owner'); + rewards.upgradeTo(address(newLogic)); + } + + function test_cantInitializeImplementationContract() public { + Rewards implementation = Rewards(get1967Implementation(address(rewards))); + + vm.expectRevert('Initializable: contract is already initialized'); + implementation.initialize(address(0), address(0), address(0), address(0)); + } +} + +contract DisablingTest is RewardsBaseTest { + function test_rewardsAreDisabledByDefault() public { + rewards = RewardsDeployer.deployRewards(dao, admin, minter, address(erc20Mock), address(0)); + assertFalse(rewards.auctionRewardsEnabled()); + } + + function test_disableRewards_revertsForNonOwner() public { + vm.prank(makeAddr('rando')); + vm.expectRevert('Ownable: caller is not the owner'); + rewards.disableAuctionRewards(); + } + + function test_disableRewards_worksForOwner() public { + vm.prank(rewards.owner()); + rewards.disableAuctionRewards(); + + assertFalse(rewards.auctionRewardsEnabled()); + } +} + +contract DisabledTest is RewardsBaseTest { + function setUp() public override { + super.setUp(); + vm.prank(rewards.owner()); + rewards.disableAuctionRewards(); + } + + function test_updateRewardsReverts() public { + vm.expectRevert(Rewards.RewardsDisabled.selector); + rewards.updateRewardsForAuctions(123); + } +} + +contract PausingTest is RewardsBaseTest { + function test_pause_revertsForNonAdminNonOwner() public { + vm.prank(makeAddr('non admin non owner')); + vm.expectRevert(Rewards.OnlyOwnerOrAdmin.selector); + rewards.pause(); + } + + function test_pause_worksForAdmin() public { + vm.prank(admin); + rewards.pause(); + + assertTrue(rewards.paused()); + } + + function test_pause_worksForOwner() public { + vm.prank(rewards.owner()); + rewards.pause(); + + assertTrue(rewards.paused()); + } +} + +contract PausedTest is RewardsBaseTest { + function setUp() public override { + super.setUp(); + + vm.prank(admin); + rewards.pause(); + } + + function test_registerClient_reverts() public { + vm.expectRevert('Pausable: paused'); + rewards.registerClient('some client', 'some description'); + } + + function test_updateRewardsForAuctions_reverts() public { + vm.expectRevert('Pausable: paused'); + rewards.updateRewardsForAuctions(1); + } + + function test_updateRewardsForProposalWritingAndVoting_reverts() public { + vm.expectRevert('Pausable: paused'); + rewards.updateRewardsForProposalWritingAndVoting(1, new uint32[](0)); + } + + function test_withdrawClientBalance_reverts() public { + vm.expectRevert('Pausable: paused'); + rewards.withdrawClientBalance(1, makeAddr('to'), 1); + } +} + +contract OwnerFunctionsTest is RewardsBaseTest { + function test_setAuctionRewardParams_revertsForNonOwner() public { + Rewards.AuctionRewardParams memory params = rewards.getAuctionRewardParams(); + + vm.prank(makeAddr('non owner')); + vm.expectRevert('Ownable: caller is not the owner'); + rewards.setAuctionRewardParams(params); + } + + function test_setProposalRewardParams_revertsForNonOwner() public { + Rewards.ProposalRewardParams memory params = rewards.getProposalRewardParams(); + + vm.prank(makeAddr('non owner')); + vm.expectRevert('Ownable: caller is not the owner'); + rewards.setProposalRewardParams(params); + } + + function test_setAdmin_revertsForNonOwner() public { + vm.prank(makeAddr('non owner')); + vm.expectRevert('Ownable: caller is not the owner'); + rewards.setAdmin(makeAddr('new admin')); + } + + function test_setAdmin_worksForOwner() public { + address newAdmin = makeAddr('new admin'); + + vm.prank(rewards.owner()); + rewards.setAdmin(newAdmin); + + assertEq(rewards.admin(), newAdmin); + } + + function test_setETHToken_revertsForNonOwner() public { + vm.prank(makeAddr('non owner')); + vm.expectRevert('Ownable: caller is not the owner'); + rewards.setETHToken(makeAddr('new token')); + } + + function test_setETHToken_worksForOwner() public { + address newToken = makeAddr('new token'); + + vm.prank(rewards.owner()); + rewards.setETHToken(newToken); + + assertEq(address(rewards.ethToken()), newToken); + } + + function test_withdrawToken_revertsForNonOwner() public { + address recipient = makeAddr('recipient'); + address token = address(rewards.ethToken()); + + vm.expectRevert('Ownable: caller is not the owner'); + vm.prank(makeAddr('non owner')); + rewards.withdrawToken(token, recipient, 1); + } + + function test_withdrawToken_worksForOwner() public { + address recipient = makeAddr('recipient'); + address token = address(rewards.ethToken()); + + vm.prank(rewards.owner()); + rewards.withdrawToken(token, recipient, 1); + + assertEq(rewards.ethToken().balanceOf(recipient), 1); + } + + function test_setClientApproval_revertsForNonOwner() public { + vm.expectRevert('Ownable: caller is not the owner'); + vm.prank(makeAddr('non owner')); + rewards.setClientApproval(1, true); + } + + function test_setClientApproval_worksForOwner() public { + assertTrue(rewards.clientMetadata(1).approved == false); + + vm.expectEmit(true, true, true, true); + emit Rewards.ClientApprovalSet(1, true); + + vm.prank(rewards.owner()); + rewards.setClientApproval(1, true); + + assertTrue(rewards.clientMetadata(1).approved); + } +} + +contract NFTFunctionsTest is RewardsBaseTest { + function setUp() public override { + dao = _deployDAOV3WithParams(24 hours); + nounsToken = NounsToken(address(dao.nouns())); + minter = nounsToken.minter(); + + auctionHouse = INounsAuctionHouseV2(minter); + vm.prank(address(dao.timelock())); + auctionHouse.unpause(); + + rewards = RewardsDeployer.deployRewards(dao, admin, minter, address(erc20Mock), address(0)); + } + + function test_registerClient_firstIdIsOne() public { + assertEq(rewards.registerClient('name', 'description'), 1); + assertEq(rewards.registerClient('name', 'description'), 2); + } + + function test_registerClient_storesMetadata() public { + uint32 tokenId = rewards.registerClient('Camp', 'https://nouns.camp'); + INounsClientTokenTypes.ClientMetadata memory md = rewards.clientMetadata(tokenId); + + assertEq(md.name, 'Camp'); + assertEq(md.description, 'https://nouns.camp'); + + tokenId = rewards.registerClient('Agora', 'https://nounsagora.com'); + md = rewards.clientMetadata(tokenId); + + assertEq(md.name, 'Agora'); + assertEq(md.description, 'https://nounsagora.com'); + } + + function test_registerClient_emitsEvent() public { + vm.expectEmit(); + emit Rewards.ClientRegistered(1, 'name', 'description'); + rewards.registerClient('name', 'description'); + } + + function test_updateClientMetadata_revertsForNonTokenOwner() public { + uint32 tokenId = rewards.registerClient('name', 'description'); + + address nonOwner = makeAddr('nonOwner'); + vm.expectRevert(Rewards.OnlyNFTOwner.selector); + vm.prank(nonOwner); + rewards.updateClientMetadata(tokenId, 'newName', 'newDescription'); + } + + function test_updateClientMetadata_worksForTokenOwner() public { + uint32 tokenId = rewards.registerClient('name', 'description'); + + rewards.updateClientMetadata(tokenId, 'newName', 'newDescription'); + INounsClientTokenTypes.ClientMetadata memory md = rewards.clientMetadata(tokenId); + + assertEq(md.name, 'newName'); + assertEq(md.description, 'newDescription'); + } + + function test_updateClientMetadata_emitsEvent() public { + uint32 tokenId = rewards.registerClient('name', 'description'); + + vm.expectEmit(); + emit Rewards.ClientUpdated(tokenId, 'newName', 'newDescription'); + rewards.updateClientMetadata(tokenId, 'newName', 'newDescription'); + } + + function test_setDescriptor_revertsForNonOwner() public { + address nonOwner = makeAddr('nonOwner'); + vm.expectRevert(Rewards.OnlyOwnerOrAdmin.selector); + vm.prank(nonOwner); + rewards.setDescriptor(address(0)); + } + + function test_setDescriptor_worksForOwner() public { + address newDescriptor = makeAddr('newDescriptor'); + + vm.prank(rewards.owner()); + rewards.setDescriptor(newDescriptor); + + assertEq(rewards.descriptor(), newDescriptor); + } + + function test_setDescriptor_worksForAdmin() public { + address newDescriptor = makeAddr('newDescriptor'); + + vm.prank(rewards.admin()); + rewards.setDescriptor(newDescriptor); + + assertEq(rewards.descriptor(), newDescriptor); + } +} diff --git a/packages/nouns-contracts/test/governance/castVote.test.ts b/packages/nouns-contracts/test/governance/castVote.test.ts index e89a7eb22e..31af03af66 100644 --- a/packages/nouns-contracts/test/governance/castVote.test.ts +++ b/packages/nouns-contracts/test/governance/castVote.test.ts @@ -21,7 +21,7 @@ import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers'; import { NounsToken, NounsDescriptorV2__factory as NounsDescriptorV2Factory, - NounsDAOLogicV3, + NounsDAOLogicV4, } from '../../typechain'; chai.use(solidity); @@ -36,7 +36,7 @@ let account1: SignerWithAddress; let account2: SignerWithAddress; let signers: TestSigners; -let gov: NounsDAOLogicV3; +let gov: INounsDAOLogic; let proposalId: EthersBN; async function reset() { diff --git a/packages/nouns-contracts/test/governance/dynamicQuorum.test.ts b/packages/nouns-contracts/test/governance/dynamicQuorum.test.ts index eaa10a8239..88f0dd6b1c 100644 --- a/packages/nouns-contracts/test/governance/dynamicQuorum.test.ts +++ b/packages/nouns-contracts/test/governance/dynamicQuorum.test.ts @@ -2,7 +2,7 @@ import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers'; import chai from 'chai'; import { solidity } from 'ethereum-waffle'; import { parseUnits } from 'ethers/lib/utils'; -import { NounsDAOLogicV3 } from '../../typechain'; +import { NounsDAOLogicV4 } from '../../typechain'; import { deployGovernorV3, getSigners, TestSigners } from '../utils'; chai.use(solidity); @@ -10,7 +10,7 @@ const { expect } = chai; let deployer: SignerWithAddress; let signers: TestSigners; -let gov: NounsDAOLogicV3; +let gov: NounsDAOLogicV4; describe('Dynamic Quorum', () => { before(async () => { diff --git a/packages/nouns-contracts/test/governance/proxy.test.ts b/packages/nouns-contracts/test/governance/proxy.test.ts index f96af20308..0be87d3b92 100644 --- a/packages/nouns-contracts/test/governance/proxy.test.ts +++ b/packages/nouns-contracts/test/governance/proxy.test.ts @@ -14,7 +14,7 @@ import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers'; import { NounsToken, NounsDescriptorV2__factory as NounsDescriptorV2Factory, - NounsDAOLogicV3, + NounsDAOLogicV4, } from '../../typechain'; import { MAX_QUORUM_VOTES_BPS, MIN_QUORUM_VOTES_BPS } from '../constants'; @@ -24,7 +24,7 @@ const { expect } = chai; let token: NounsToken; let deployer: SignerWithAddress; let signers: TestSigners; -let gov: NounsDAOLogicV3; +let gov: NounsDAOLogicV4; async function setup() { token = await deployNounsToken(signers.deployer); diff --git a/packages/nouns-contracts/test/governance/quorumConfig.test.ts b/packages/nouns-contracts/test/governance/quorumConfig.test.ts index 9e8581d778..5ab7f05e1f 100644 --- a/packages/nouns-contracts/test/governance/quorumConfig.test.ts +++ b/packages/nouns-contracts/test/governance/quorumConfig.test.ts @@ -6,17 +6,17 @@ import { getSigners, TestSigners, setTotalSupply, - deployGovernorV1, blockNumber, advanceBlocks, populateDescriptorV2, - deployGovernorV3AndSetImpl, + deployGovernorV3WithV3Proxy, } from '../utils'; import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers'; import { NounsToken, NounsDescriptorV2__factory as NounsDescriptorV2Factory, - NounsDAOLogicV3, + INounsDAOLogic, + NounsDAOLogicV4__factory, } from '../../typechain'; import { parseUnits } from 'ethers/lib/utils'; import { DynamicQuorumParams } from '../types'; @@ -29,7 +29,7 @@ let token: NounsToken; let deployer: SignerWithAddress; let account0: SignerWithAddress; let signers: TestSigners; -let gov: NounsDAOLogicV3; +let gov: INounsDAOLogic; let snapshotId: number; const V1_QUORUM_BPS = 201; @@ -43,13 +43,7 @@ async function setup() { await setTotalSupply(token, 100); - const { address: govProxyAddress } = await deployGovernorV1( - deployer, - token.address, - V1_QUORUM_BPS, - ); - - gov = await deployGovernorV3AndSetImpl(deployer, govProxyAddress); + gov = await deployGovernorV3WithV3Proxy(deployer, token.address); } describe('NounsDAO#_setDynamicQuorumParams', () => { @@ -70,16 +64,6 @@ describe('NounsDAO#_setDynamicQuorumParams', () => { }); describe('allowed values', () => { - it('returns default values if no config set yet', async () => { - const params = await gov.getDynamicQuorumParamsAt(await blockNumber()); - - expectEqualParams(params, { - minQuorumVotesBPS: V1_QUORUM_BPS, - maxQuorumVotesBPS: V1_QUORUM_BPS, - quorumCoefficient: 0, - }); - }); - it('reverts when sender is not admin [ @skip-on-coverage ]', async () => { await expect(gov.connect(account0)._setDynamicQuorumParams(0, 0, 0)).to.be.revertedWith( 'AdminOnly()', @@ -123,25 +107,14 @@ describe('NounsDAO#_setDynamicQuorumParams', () => { expect(actualParams.maxQuorumVotesBPS).to.equal(2222); expect(actualParams.quorumCoefficient).to.equal(quorumCoefficient); - await expect(tx).to.emit(gov, 'MinQuorumVotesBPSSet').withArgs(200, 222); - await expect(tx).to.emit(gov, 'MaxQuorumVotesBPSSet').withArgs(2000, 2222); - await expect(tx) - .to.emit(gov, 'QuorumCoefficientSet') - .withArgs(parseUnits('1', 6), quorumCoefficient); - }); - - it('given no prior config, sets value and emits event', async () => { - const quorumCoefficient = parseUnits('1', 6); - const tx = await gov._setDynamicQuorumParams(200, 4000, quorumCoefficient); + let govWithEvents = NounsDAOLogicV4__factory.connect(gov.address, gov.signer); - const actualParams = await gov.getDynamicQuorumParamsAt(await blockNumber()); - expect(actualParams.minQuorumVotesBPS).to.equal(200); - expect(actualParams.maxQuorumVotesBPS).to.equal(4000); - expect(actualParams.quorumCoefficient).to.equal(quorumCoefficient); + await expect(tx).to.emit(govWithEvents, 'MinQuorumVotesBPSSet').withArgs(200, 222); + await expect(tx).to.emit(govWithEvents, 'MaxQuorumVotesBPSSet').withArgs(2000, 2222); - await expect(tx).to.emit(gov, 'MinQuorumVotesBPSSet').withArgs(V1_QUORUM_BPS, 200); - await expect(tx).to.emit(gov, 'MaxQuorumVotesBPSSet').withArgs(V1_QUORUM_BPS, 4000); - await expect(tx).to.emit(gov, 'QuorumCoefficientSet').withArgs(0, quorumCoefficient); + await expect(tx) + .to.emit(govWithEvents, 'QuorumCoefficientSet') + .withArgs(parseUnits('1', 6), quorumCoefficient); }); describe('quorum params checkpointing', () => { @@ -197,16 +170,6 @@ describe('NounsDAO#_setDynamicQuorumParams', () => { expectEqualParams(await gov.getDynamicQuorumParamsAt(blockNum3), params3); }); - it('returns default values if block number too low', async () => { - const params = await gov.getDynamicQuorumParamsAt(blockNum1 - 2); - - expectEqualParams(params, { - minQuorumVotesBPS: V1_QUORUM_BPS, - maxQuorumVotesBPS: V1_QUORUM_BPS, - quorumCoefficient: 0, - }); - }); - it('reads correct values in between block numbers', async () => { expectEqualParams(await gov.getDynamicQuorumParamsAt(blockNum1 + 5), params1); expectEqualParams(await gov.getDynamicQuorumParamsAt(blockNum2 + 5), params2); @@ -238,7 +201,8 @@ describe('NounsDAO#_setDynamicQuorumParams', () => { const params = await gov.getDynamicQuorumParamsAt(await blockNumber()); expect(params.minQuorumVotesBPS).to.equal(222); - await expect(tx).to.emit(gov, 'MinQuorumVotesBPSSet').withArgs(200, 222); + let govWithEvents = NounsDAOLogicV4__factory.connect(gov.address, gov.signer); + await expect(tx).to.emit(govWithEvents, 'MinQuorumVotesBPSSet').withArgs(200, 222); }); it('reverts when sender is not admin [ @skip-on-coverage ]', async () => { @@ -274,7 +238,8 @@ describe('NounsDAO#_setDynamicQuorumParams', () => { const params = await gov.getDynamicQuorumParamsAt(await blockNumber()); expect(params.maxQuorumVotesBPS).to.equal(3333); - await expect(tx).to.emit(gov, 'MaxQuorumVotesBPSSet').withArgs(3000, 3333); + let govWithEvents = NounsDAOLogicV4__factory.connect(gov.address, gov.signer); + await expect(tx).to.emit(govWithEvents, 'MaxQuorumVotesBPSSet').withArgs(3000, 3333); }); it('reverts when sender is not admin [ @skip-on-coverage ]', async () => { @@ -302,7 +267,8 @@ describe('NounsDAO#_setDynamicQuorumParams', () => { const params = await gov.getDynamicQuorumParamsAt(await blockNumber()); expect(params.quorumCoefficient).to.equal(111); - await expect(tx).to.emit(gov, 'QuorumCoefficientSet').withArgs(1, 111); + let govWithEvents = NounsDAOLogicV4__factory.connect(gov.address, gov.signer); + await expect(tx).to.emit(govWithEvents, 'QuorumCoefficientSet').withArgs(1, 111); }); it('reverts when sender is not admin [ @skip-on-coverage ]', async () => { diff --git a/packages/nouns-contracts/test/governance/voteRefund.test.ts b/packages/nouns-contracts/test/governance/voteRefund.test.ts index 66f3adcaf5..72eee72538 100644 --- a/packages/nouns-contracts/test/governance/voteRefund.test.ts +++ b/packages/nouns-contracts/test/governance/voteRefund.test.ts @@ -4,11 +4,12 @@ import { solidity } from 'ethereum-waffle'; import { BigNumber, ContractReceipt } from 'ethers'; import { ethers } from 'hardhat'; import { - NounsDAOLogicV3__factory, - NounsDAOLogicV3, + NounsDAOLogicV4__factory, + NounsDAOLogicV4, NounsDescriptorV2__factory, NounsToken, Voter__factory, + INounsDAOLogic, } from '../../typechain'; import { MaliciousVoter__factory } from '../../typechain/factories/contracts/test/MaliciousVoter__factory'; import { @@ -39,7 +40,7 @@ let deployer: SignerWithAddress; let user: SignerWithAddress; let user2: SignerWithAddress; let signers: TestSigners; -let gov: NounsDAOLogicV3; +let gov: INounsDAOLogic; let token: NounsToken; let snapshotId: number; @@ -76,21 +77,28 @@ describe('V3 Vote Refund', () => { it('refunds users with votes', async () => { await fundGov(); const balanceBefore = await user.getBalance(); - const tx = await gov.connect(user).castRefundableVote(1, 1, DEFAULT_GAS_OPTIONS); + const tx = await gov + .connect(user) + ['castRefundableVote(uint256,uint8)'](1, 1, DEFAULT_GAS_OPTIONS); const r = await tx.wait(); const balanceDiff = balanceBefore.sub(await user.getBalance()); expect(r.gasUsed).to.be.gt(0); expect(balanceDiff).to.be.closeTo(BigNumber.from(0), REFUND_ERROR_MARGIN); expectRefundEvent(r, user, await txCostInEth(r)); - await expect(tx).to.emit(gov, 'VoteCast').withArgs(user.address, BigNumber.from(1), 1, 2, ''); + let govWithEvents = NounsDAOLogicV4__factory.connect(gov.address, gov.signer); + await expect(tx) + .to.emit(govWithEvents, 'VoteCast') + .withArgs(user.address, BigNumber.from(1), 1, 2, ''); }); it('does not refund users with no votes', async () => { await fundGov(); const balanceBefore = await user2.getBalance(); - const tx = await gov.connect(user2).castRefundableVote(1, 1, DEFAULT_GAS_OPTIONS); + const tx = await gov + .connect(user2) + ['castRefundableVote(uint256,uint8)'](1, 1, DEFAULT_GAS_OPTIONS); const r = await tx.wait(); expect(r.gasUsed).to.be.gt(0); @@ -103,7 +111,7 @@ describe('V3 Vote Refund', () => { await fundGov(); const balanceBefore = await user.getBalance(); - const tx = await gov.connect(user).castRefundableVote(1, 1, { + const tx = await gov.connect(user)['castRefundableVote(uint256,uint8)'](1, 1, { maxPriorityFeePerGas: ethers.utils.parseUnits('80', 'gwei'), }); const r = await tx.wait(); @@ -119,7 +127,9 @@ describe('V3 Vote Refund', () => { it('does not refund when DAO balance is zero', async () => { expect(await ethers.provider.getBalance(gov.address)).to.eq(0); const balanceBefore = await user.getBalance(); - const tx = await gov.connect(user).castRefundableVote(1, 1, DEFAULT_GAS_OPTIONS); + const tx = await gov + .connect(user) + ['castRefundableVote(uint256,uint8)'](1, 1, DEFAULT_GAS_OPTIONS); const r = await tx.wait(); expect(r.gasUsed).to.be.gt(0); @@ -133,7 +143,9 @@ describe('V3 Vote Refund', () => { expect(await ethers.provider.getBalance(gov.address)).to.eq(govBalance); const balanceBefore = await user.getBalance(); - const tx = await gov.connect(user).castRefundableVote(1, 1, DEFAULT_GAS_OPTIONS); + const tx = await gov + .connect(user) + ['castRefundableVote(uint256,uint8)'](1, 1, DEFAULT_GAS_OPTIONS); const r = await tx.wait(); expect(r.gasUsed).to.be.gt(0); @@ -165,7 +177,12 @@ describe('V3 Vote Refund', () => { const balanceBefore = await user.getBalance(); const tx = await gov .connect(user) - .castRefundableVoteWithReason(1, 1, 'some reason', DEFAULT_GAS_OPTIONS); + ['castRefundableVoteWithReason(uint256,uint8,string)']( + 1, + 1, + 'some reason', + DEFAULT_GAS_OPTIONS, + ); const r = await tx.wait(); const balanceDiff = balanceBefore.sub(await user.getBalance()); @@ -173,8 +190,9 @@ describe('V3 Vote Refund', () => { expect(balanceDiff).to.be.closeTo(BigNumber.from(0), REFUND_ERROR_MARGIN); expectRefundEvent(r, user, await txCostInEth(r)); + let govWithEvents = NounsDAOLogicV4__factory.connect(gov.address, gov.signer); await expect(tx) - .to.emit(gov, 'VoteCast') + .to.emit(govWithEvents, 'VoteCast') .withArgs(user.address, BigNumber.from(1), 1, 2, 'some reason'); }); @@ -184,7 +202,12 @@ describe('V3 Vote Refund', () => { const tx = await gov .connect(user2) - .castRefundableVoteWithReason(1, 1, 'some reason', DEFAULT_GAS_OPTIONS); + ['castRefundableVoteWithReason(uint256,uint8,string)']( + 1, + 1, + 'some reason', + DEFAULT_GAS_OPTIONS, + ); const r = await tx.wait(); expect(r.gasUsed).to.be.gt(0); @@ -197,9 +220,11 @@ describe('V3 Vote Refund', () => { await fundGov(); const balanceBefore = await user.getBalance(); - const tx = await gov.connect(user).castRefundableVoteWithReason(1, 1, 'some reason', { - maxPriorityFeePerGas: ethers.utils.parseUnits('80', 'gwei'), - }); + const tx = await gov + .connect(user) + ['castRefundableVoteWithReason(uint256,uint8,string)'](1, 1, 'some reason', { + maxPriorityFeePerGas: ethers.utils.parseUnits('80', 'gwei'), + }); const r = await tx.wait(); expect(r.gasUsed).to.be.gt(0); @@ -215,7 +240,12 @@ describe('V3 Vote Refund', () => { const balanceBefore = await user.getBalance(); const tx = await gov .connect(user) - .castRefundableVoteWithReason(1, 1, LONG_REASON, DEFAULT_GAS_OPTIONS); + ['castRefundableVoteWithReason(uint256,uint8,string)']( + 1, + 1, + LONG_REASON, + DEFAULT_GAS_OPTIONS, + ); const r = await tx.wait(); const balanceDiff = balanceBefore.sub(await user.getBalance()); @@ -223,8 +253,9 @@ describe('V3 Vote Refund', () => { expect(balanceDiff).to.be.closeTo(await expectedGasUsedCappedDiff(r), REFUND_ERROR_MARGIN); expectRefundEvent(r, user, MAX_REFUND_GAS_USED.mul(await latestBasePlusMaxPriority())); + let govWithEvents = NounsDAOLogicV4__factory.connect(gov.address, gov.signer); await expect(tx) - .to.emit(gov, 'VoteCast') + .to.emit(govWithEvents, 'VoteCast') .withArgs(user.address, BigNumber.from(1), 1, 2, LONG_REASON); }); @@ -234,7 +265,12 @@ describe('V3 Vote Refund', () => { const balanceBefore = await user.getBalance(); const tx = await gov .connect(user) - .castRefundableVoteWithReason(1, 1, 'some reason', DEFAULT_GAS_OPTIONS); + ['castRefundableVoteWithReason(uint256,uint8,string)']( + 1, + 1, + 'some reason', + DEFAULT_GAS_OPTIONS, + ); const r = await tx.wait(); const balanceDiff = balanceBefore.sub(await user.getBalance()); @@ -242,8 +278,9 @@ describe('V3 Vote Refund', () => { expect(balanceDiff).to.be.closeTo(await expectedBaseFeeCappedDiff(r), REFUND_ERROR_MARGIN); expectRefundEvent(r, user, r.gasUsed.mul(MAX_REFUND_BASE_FEE.add(MAX_PRIORITY_FEE_CAP))); + let govWithEvents = NounsDAOLogicV4__factory.connect(gov.address, gov.signer); await expect(tx) - .to.emit(gov, 'VoteCast') + .to.emit(govWithEvents, 'VoteCast') .withArgs(user.address, BigNumber.from(1), 1, 2, 'some reason'); }); @@ -252,7 +289,12 @@ describe('V3 Vote Refund', () => { const balanceBefore = await user.getBalance(); const tx = await gov .connect(user) - .castRefundableVoteWithReason(1, 1, 'some reason', DEFAULT_GAS_OPTIONS); + ['castRefundableVoteWithReason(uint256,uint8,string)']( + 1, + 1, + 'some reason', + DEFAULT_GAS_OPTIONS, + ); const r = await tx.wait(); expect(r.gasUsed).to.be.gt(0); @@ -268,7 +310,12 @@ describe('V3 Vote Refund', () => { const tx = await gov .connect(user) - .castRefundableVoteWithReason(1, 1, 'some reason', DEFAULT_GAS_OPTIONS); + ['castRefundableVoteWithReason(uint256,uint8,string)']( + 1, + 1, + 'some reason', + DEFAULT_GAS_OPTIONS, + ); const r = await tx.wait(); expect(r.gasUsed).to.be.gt(0); @@ -311,8 +358,9 @@ describe('V3 Vote Refund', () => { expect(balanceDiff).to.be.closeTo(BigNumber.from(0), REFUND_ERROR_MARGIN); expectRefundEvent(r, user, await txCostInEth(r)); + let govWithEvents = NounsDAOLogicV4__factory.connect(gov.address, gov.signer); await expect(tx) - .to.emit(gov, 'VoteCast') + .to.emit(govWithEvents, 'VoteCast') .withArgs(voter.address, BigNumber.from(2), 1, 1, 'some reason'); }); }); @@ -353,7 +401,7 @@ describe('V3 Vote Refund', () => { // Not using expect emit because it doesn't support the `closeTo` matcher // Using longer event parsing because r.events doesn't work when using the Voter contract // to simulate multisig usage; events are returned undefined - const daoInterface = NounsDAOLogicV3__factory.createInterface(); + const daoInterface = NounsDAOLogicV4__factory.createInterface(); const eventId = ethers.utils.id('RefundableVote(address,uint256,bool)'); const filtered = r.logs.filter(l => l.topics[0] === eventId); const parsed = filtered.map(e => { @@ -371,7 +419,7 @@ describe('V3 Vote Refund', () => { async function submitProposal(u: SignerWithAddress) { await gov .connect(u) - .propose( + ['propose(address[],uint256[],string[],bytes[],string)']( [address(0)], ['0'], ['getBalanceOf(address)'], diff --git a/packages/nouns-contracts/test/utils.ts b/packages/nouns-contracts/test/utils.ts index 77beb5914e..06cd632e76 100644 --- a/packages/nouns-contracts/test/utils.ts +++ b/packages/nouns-contracts/test/utils.ts @@ -25,10 +25,12 @@ import { NounsDAOExecutor, Inflator__factory, NounsDAOStorageV2, - NounsDAOLogicV3, - NounsDAOLogicV3__factory as NounsDaoLogicV3Factory, + NounsDAOLogicV4, + NounsDAOLogicV4__factory as NounsDaoLogicFactory, NounsDAOProxyV3__factory as NounsDaoProxyV3Factory, NounsDAOForkEscrow__factory as NounsDAOForkEscrowFactory, + INounsDAOLogic__factory, + INounsDAOLogic, } from '../typechain'; import ImageData from '../files/image-data-v1.json'; import ImageDataV2 from '../files/image-data-v2.json'; @@ -498,7 +500,7 @@ export const deployGovernorV2AndSetQuorumParams = async ( }; export const propose = async ( - gov: NounsDAOLogicV1 | NounsDAOLogicV2 | NounsDAOLogicV3, + gov: INounsDAOLogic, proposer: SignerWithAddress, stubPropUserAddress: string = address(0), ) => { @@ -507,7 +509,15 @@ export const propose = async ( const signatures = ['getBalanceOf(address)']; const callDatas = [encodeParameters(['address'], [stubPropUserAddress])]; - await gov.connect(proposer).propose(targets, values, signatures, callDatas, 'do nothing'); + await gov + .connect(proposer) + ['propose(address[],uint256[],string[],bytes[],string)']( + targets, + values, + signatures, + callDatas, + 'do nothing', + ); return await gov.latestProposalIds(proposer.address); }; @@ -531,32 +541,25 @@ function dataToDescriptorInput(data: string[]): { }; } -export const deployGovernorV3 = async (deployer: SignerWithAddress): Promise => { - const NounsDAOV3Proposals = await ( - await ethers.getContractFactory('NounsDAOV3Proposals', deployer) +export const deployGovernorV3 = async (deployer: SignerWithAddress): Promise => { + const NounsDAOProposals = await ( + await ethers.getContractFactory('NounsDAOProposals', deployer) ).deploy(); - const NounsDAOV3Admin = await ( - await ethers.getContractFactory('NounsDAOV3Admin', deployer) - ).deploy(); - const NounsDAOV3Fork = await ( - await ethers.getContractFactory('NounsDAOV3Fork', deployer) - ).deploy(); - const NounsDAOV3Votes = await ( - await ethers.getContractFactory('NounsDAOV3Votes', deployer) - ).deploy(); - const NounsDAOV3DynamicQuorum = await ( - await ethers.getContractFactory('NounsDAOV3DynamicQuorum', deployer) + const NounsDAOAdmin = await (await ethers.getContractFactory('NounsDAOAdmin', deployer)).deploy(); + const NounsDAOFork = await (await ethers.getContractFactory('NounsDAOFork', deployer)).deploy(); + const NounsDAOVotes = await (await ethers.getContractFactory('NounsDAOVotes', deployer)).deploy(); + const NounsDAODynamicQuorum = await ( + await ethers.getContractFactory('NounsDAODynamicQuorum', deployer) ).deploy(); - return await new NounsDaoLogicV3Factory( + return await new NounsDaoLogicFactory( { - 'contracts/governance/NounsDAOV3Proposals.sol:NounsDAOV3Proposals': - NounsDAOV3Proposals.address, - 'contracts/governance/NounsDAOV3Admin.sol:NounsDAOV3Admin': NounsDAOV3Admin.address, - 'contracts/governance/fork/NounsDAOV3Fork.sol:NounsDAOV3Fork': NounsDAOV3Fork.address, - 'contracts/governance/NounsDAOV3Votes.sol:NounsDAOV3Votes': NounsDAOV3Votes.address, - 'contracts/governance/NounsDAOV3DynamicQuorum.sol:NounsDAOV3DynamicQuorum': - NounsDAOV3DynamicQuorum.address, + 'contracts/governance/NounsDAOAdmin.sol:NounsDAOAdmin': NounsDAOAdmin.address, + 'contracts/governance/NounsDAOProposals.sol:NounsDAOProposals': NounsDAOProposals.address, + 'contracts/governance/fork/NounsDAOFork.sol:NounsDAOFork': NounsDAOFork.address, + 'contracts/governance/NounsDAOVotes.sol:NounsDAOVotes': NounsDAOVotes.address, + 'contracts/governance/NounsDAODynamicQuorum.sol:NounsDAODynamicQuorum': + NounsDAODynamicQuorum.address, }, deployer, ).deploy(); @@ -565,13 +568,13 @@ export const deployGovernorV3 = async (deployer: SignerWithAddress): Promise => { +): Promise => { const v3LogicContract = await deployGovernorV3(deployer); const proxy = NounsDaoProxyFactory.connect(proxyAddress, deployer); await proxy._setImplementation(v3LogicContract.address); - return NounsDaoLogicV3Factory.connect(proxyAddress, deployer); + return INounsDAOLogic__factory.connect(proxyAddress, deployer); }; export const deployGovernorV3WithV3Proxy = async ( @@ -584,7 +587,7 @@ export const deployGovernorV3WithV3Proxy = async ( votingDelay?: number, proposalThresholdBPs?: number, dynamicQuorumParams?: DynamicQuorumParams, -): Promise => { +): Promise => { const v3LogicContract = await deployGovernorV3(deployer); const predictedProxyAddress = ethers.utils.getContractAddress({ from: deployer.address, @@ -618,5 +621,5 @@ export const deployGovernorV3WithV3Proxy = async ( }, ); - return NounsDaoLogicV3Factory.connect(proxy.address, deployer); + return INounsDAOLogic__factory.connect(proxy.address, deployer); }; diff --git a/packages/nouns-sdk/src/contract/contracts.ts b/packages/nouns-sdk/src/contract/contracts.ts index 45823232e9..e713c74952 100644 --- a/packages/nouns-sdk/src/contract/contracts.ts +++ b/packages/nouns-sdk/src/contract/contracts.ts @@ -3,7 +3,7 @@ import { NounsAuctionHouseFactory, NounsDescriptorFactory, NounsSeederFactory, - NounsDaoLogicV2Factory, + NounsDaoLogicFactory, } from '@nouns/contracts'; import type { Signer } from 'ethers'; import type { Provider } from '@ethersproject/providers'; @@ -40,7 +40,7 @@ export const getContractsForChainOrThrow = ( addresses.nounsSeeder, signerOrProvider as Signer | Provider, ), - nounsDaoContract: NounsDaoLogicV2Factory.connect( + nounsDaoContract: NounsDaoLogicFactory.connect( addresses.nounsDAOProxy, signerOrProvider as Signer | Provider, ), diff --git a/packages/nouns-sdk/src/contract/index.ts b/packages/nouns-sdk/src/contract/index.ts index 193094c774..f86defe217 100644 --- a/packages/nouns-sdk/src/contract/index.ts +++ b/packages/nouns-sdk/src/contract/index.ts @@ -6,16 +6,12 @@ export { NounsAuctionHouseABI, NounsDescriptorABI, NounsSeederABI, - NounsDAOABI, - NounsDAOV2ABI, NounsDAOV3ABI, NounsDAOExecutorV2ABI, NounsTokenFactory, NounsAuctionHouseFactory, NounsDescriptorFactory, NounsSeederFactory, - NounsDaoLogicV1Factory, - NounsDaoLogicV2Factory, - NounsDaoLogicV3Factory, + NounsDaoLogicFactory, NounsDaoExecutorV2Factory, } from '@nouns/contracts'; diff --git a/packages/nouns-sdk/src/contract/types.ts b/packages/nouns-sdk/src/contract/types.ts index 7079508cbd..9dde93a386 100644 --- a/packages/nouns-sdk/src/contract/types.ts +++ b/packages/nouns-sdk/src/contract/types.ts @@ -3,7 +3,7 @@ import { NounsAuctionHouseFactory, NounsDescriptorFactory, NounsSeederFactory, - NounsDaoLogicV2Factory, + NounsDaoLogicFactory, } from '@nouns/contracts'; export interface ContractAddresses { @@ -20,7 +20,7 @@ export interface ContractAddresses { nounsDAOProxy: string; nounsDAOLogicV1?: string; nounsDAOLogicV2?: string; - nounsDAOLogicV3?: string; + NounsDAOLogicV4?: string; nounsDAOData?: string; } @@ -29,7 +29,7 @@ export interface Contracts { nounsAuctionHouseContract: ReturnType; nounsDescriptorContract: ReturnType; nounsSeederContract: ReturnType; - nounsDaoContract: ReturnType; + nounsDaoContract: ReturnType; } export enum ChainId { diff --git a/packages/nouns-subgraph/config/sepolia.json b/packages/nouns-subgraph/config/sepolia.json index d32289d597..34b1f324ec 100644 --- a/packages/nouns-subgraph/config/sepolia.json +++ b/packages/nouns-subgraph/config/sepolia.json @@ -1,19 +1,19 @@ { "network": "sepolia", "nounsToken": { - "address": "0x4C4674bb72a096855496a7204962297bd7e12b85", - "startBlock": 3594636 + "address": "0x03439d47983d48C0402D2e88C5F8368d6B6BaC77", + "startBlock": 5301488 }, "nounsAuctionHouse": { - "address": "0x488609b7113FCf3B761A05956300d605E8f6BcAf", - "startBlock": 3594636 + "address": "0x09BD4d1066a2f4AD4445f60De356bfc9494b5C0d", + "startBlock": 5301519 }, "nounsDAO": { - "address": "0x35d2670d7C8931AACdd37C89Ddcb0638c3c44A57", - "startBlock": 3594636 + "address": "0x442961F79C3968f908ed295a5DEbfcD9aC1712B6", + "startBlock": 5301556 }, "nounsDAOData": { - "address": "0x9040f720AA8A693F950B9cF94764b4b06079D002", - "startBlock": 3594636 + "address": "0xF82152a4322800E15F14eD85e490Fe12b815E6c3", + "startBlock": 5301568 } } diff --git a/packages/nouns-subgraph/package.json b/packages/nouns-subgraph/package.json index 1cc2fe1352..c4336316f9 100644 --- a/packages/nouns-subgraph/package.json +++ b/packages/nouns-subgraph/package.json @@ -26,8 +26,8 @@ "deploy:hardhat": "yarn clean && yarn prepare:hardhat && yarn codegen && yarn create:localnode nounsdao/nouns-subgraph && yarn deploy:localnode nounsdao/nouns-subgraph", "deploy:rinkeby": "yarn clean && yarn prepare:rinkeby && yarn codegen && yarn deploy nounsdao/nouns-subgraph-rinkeby", "deploy:goerli": "yarn clean && yarn prepare:goerli && yarn codegen && yarn graph build && goldsky subgraph deploy nouns-v3-goerli/0.1.6", - "deploy:sepolia": "yarn clean && yarn prepare:sepolia && yarn codegen && yarn graph build && goldsky subgraph deploy nouns-sepolia/0.1.6", - "deploy:mainnet": "yarn clean && yarn prepare:mainnet && yarn codegen && yarn graph build && goldsky subgraph deploy nouns/0.2.0", + "deploy:sepolia": "yarn clean && yarn prepare:sepolia && yarn codegen && yarn graph build && goldsky subgraph deploy nouns-sepolia-client-incentives/0.1.1", + "deploy:mainnet": "yarn clean && yarn prepare:mainnet && yarn codegen && yarn graph build && goldsky subgraph deploy nouns/0.2.5", "mustache": "mustache" }, "devDependencies": { diff --git a/packages/nouns-subgraph/schema.graphql b/packages/nouns-subgraph/schema.graphql index e2b49c00d7..f1c3b9d653 100644 --- a/packages/nouns-subgraph/schema.graphql +++ b/packages/nouns-subgraph/schema.graphql @@ -99,6 +99,9 @@ type Bid @entity { "The timestamp of the block the bid is in" blockTimestamp: BigInt! + + "The ID of the client that facilitated this bid" + clientId: Int } type Auction @entity { @@ -123,6 +126,8 @@ type Auction @entity { "Whether or not the auction has been settled" settled: Boolean! + clientId: Int! + "The auction bids" bids: [Bid!]! @derivedFrom(field: "auction") } @@ -228,10 +233,10 @@ type Proposal @entity { endBlock: BigInt! "The proposal threshold at the time of proposal creation" - proposalThreshold: BigInt! + proposalThreshold: BigInt "The required number of votes for quorum at the time of proposal creation" - quorumVotes: BigInt! + quorumVotes: BigInt "The number of votes in favor of the proposal" forVotes: BigInt! @@ -249,7 +254,7 @@ type Proposal @entity { description: String! "Status of the proposal" - status: ProposalStatus! + status: ProposalStatus "Once the proposal is queued for execution it will have an ETA of the execution" executionETA: BigInt @@ -276,7 +281,7 @@ type Proposal @entity { objectionPeriodEndBlock: BigInt! "The update period end block" - updatePeriodEndBlock: BigInt! + updatePeriodEndBlock: BigInt "Feedback posts associated to this proposal" feedbackPosts: [ProposalFeedback!]! @derivedFrom(field: "proposal") @@ -310,6 +315,9 @@ type Proposal @entity { "The timestamp when this proposal was queued" queuedTimestamp: BigInt + + "The ID of the client that facilitated this proposal" + clientId: Int! } type ProposalVersion @entity(immutable: true) { @@ -379,6 +387,9 @@ type Vote @entity { "The timestamp of the block the vote is in" blockTimestamp: BigInt! + + "The ID of the client that facilitated this vote" + clientId: Int! } type Governance @entity { diff --git a/packages/nouns-subgraph/src/custom-types/ParsedProposalV3.ts b/packages/nouns-subgraph/src/custom-types/ParsedProposalV3.ts index abfdccc3bf..8ed21adaa5 100644 --- a/packages/nouns-subgraph/src/custom-types/ParsedProposalV3.ts +++ b/packages/nouns-subgraph/src/custom-types/ParsedProposalV3.ts @@ -1,80 +1,36 @@ -import { BigInt, Bytes } from '@graphprotocol/graph-ts'; +import { BigInt } from '@graphprotocol/graph-ts'; import { - NounsDAO, ProposalCreatedWithRequirements, ProposalCreatedWithRequirements1, } from '../types/NounsDAO/NounsDAO'; -import { BIGINT_ZERO, STATUS_ACTIVE, STATUS_PENDING } from '../utils/constants'; +import { ProposalCreatedWithRequirements1 as ProposalCreatedWithRequirementsV4 } from '../types/NounsDAOV4/NounsDAOV4'; +import { BIGINT_ZERO } from '../utils/constants'; export class ParsedProposalV3 { id: string = ''; - proposer: string = ''; txHash: string = ''; - logIndex: string = ''; - targets: Bytes[] = []; - values: BigInt[] = []; - signatures: string[] = []; - calldatas: Bytes[] = []; - createdTimestamp: BigInt = BIGINT_ZERO; - createdBlock: BigInt = BIGINT_ZERO; - createdTransactionHash: Bytes = Bytes.fromI32(0); - startBlock: BigInt = BIGINT_ZERO; - endBlock: BigInt = BIGINT_ZERO; updatePeriodEndBlock: BigInt = BIGINT_ZERO; proposalThreshold: BigInt = BIGINT_ZERO; quorumVotes: BigInt = BIGINT_ZERO; - description: string = ''; - title: string = ''; - status: string = ''; signers: string[] = []; - adjustedTotalSupply: BigInt = BIGINT_ZERO; + clientId: BigInt = BIGINT_ZERO; static fromV1Event(event: ProposalCreatedWithRequirements1): ParsedProposalV3 { const proposal = new ParsedProposalV3(); - proposal.id = event.params.id.toString(); - proposal.proposer = event.params.proposer.toHexString(); proposal.txHash = event.transaction.hash.toHexString(); - proposal.logIndex = event.logIndex.toString(); - proposal.targets = changetype(event.params.targets); - proposal.values = event.params.values; - proposal.signatures = event.params.signatures; - proposal.calldatas = event.params.calldatas; - proposal.createdTimestamp = event.block.timestamp; - proposal.createdBlock = event.block.number; - proposal.createdTransactionHash = event.transaction.hash; - proposal.startBlock = event.params.startBlock; - proposal.endBlock = event.params.endBlock; proposal.proposalThreshold = event.params.proposalThreshold; proposal.quorumVotes = event.params.quorumVotes; - proposal.description = event.params.description.split('\\n').join('\n'); // The Graph's AssemblyScript version does not support string.replace - proposal.title = extractTitle(proposal.description); - proposal.status = event.block.number >= proposal.startBlock ? STATUS_ACTIVE : STATUS_PENDING; return proposal; } static fromV3Event(event: ProposalCreatedWithRequirements): ParsedProposalV3 { const proposal = new ParsedProposalV3(); - const nounsDAO = NounsDAO.bind(event.address); - proposal.id = event.params.id.toString(); - proposal.proposer = event.params.proposer.toHexString(); proposal.txHash = event.transaction.hash.toHexString(); - proposal.targets = changetype(event.params.targets); - proposal.values = event.params.values; - proposal.signatures = event.params.signatures; - proposal.calldatas = event.params.calldatas; - proposal.createdTimestamp = event.block.timestamp; - proposal.createdBlock = event.block.number; - proposal.createdTransactionHash = event.transaction.hash; - proposal.startBlock = event.params.startBlock; - proposal.endBlock = event.params.endBlock; proposal.proposalThreshold = event.params.proposalThreshold; proposal.quorumVotes = event.params.quorumVotes; - proposal.description = event.params.description.split('\\n').join('\n'); // The Graph's AssemblyScript version does not support string.replace - proposal.title = extractTitle(proposal.description); - proposal.status = event.block.number >= proposal.startBlock ? STATUS_ACTIVE : STATUS_PENDING; proposal.signers = new Array(event.params.signers.length); for (let i = 0; i < event.params.signers.length; i++) { @@ -82,7 +38,24 @@ export class ParsedProposalV3 { } proposal.updatePeriodEndBlock = event.params.updatePeriodEndBlock; - proposal.adjustedTotalSupply = nounsDAO.adjustedTotalSupply(); + + return proposal; + } + + static fromV4Event(event: ProposalCreatedWithRequirementsV4): ParsedProposalV3 { + const proposal = new ParsedProposalV3(); + proposal.id = event.params.id.toString(); + proposal.txHash = event.transaction.hash.toHexString(); + proposal.proposalThreshold = event.params.proposalThreshold; + proposal.quorumVotes = event.params.quorumVotes; + proposal.signers = new Array(event.params.signers.length); + for (let i = 0; i < event.params.signers.length; i++) { + proposal.signers[i] = event.params.signers[i].toHexString(); + } + + proposal.updatePeriodEndBlock = event.params.updatePeriodEndBlock; + + proposal.clientId = event.params.clientId; return proposal; } diff --git a/packages/nouns-subgraph/src/nouns-auction-house.ts b/packages/nouns-subgraph/src/nouns-auction-house.ts index b45320797f..cb2194134e 100644 --- a/packages/nouns-subgraph/src/nouns-auction-house.ts +++ b/packages/nouns-subgraph/src/nouns-auction-house.ts @@ -5,6 +5,10 @@ import { AuctionExtended, AuctionSettled, } from './types/NounsAuctionHouse/NounsAuctionHouse'; +import { + AuctionSettledWithClientId, + AuctionBidWithClientId, +} from './types/NounsAuctionHouseV2/NounsAuctionHouseV2'; import { Auction, Noun, Bid } from './types/schema'; import { getOrCreateAccount } from './utils/helpers'; @@ -26,19 +30,16 @@ export function handleAuctionCreated(event: AuctionCreated): void { auction.startTime = event.params.startTime; auction.endTime = event.params.endTime; auction.settled = false; + auction.clientId = 0; auction.save(); } export function handleAuctionBid(event: AuctionBid): void { - let nounId = event.params.nounId.toString(); - let bidderAddress = event.params.sender.toHex(); - - let bidder = getOrCreateAccount(bidderAddress); - - let auction = Auction.load(nounId); + let bidder = getOrCreateAccount(event.params.sender.toHex()); + let auction = Auction.load(event.params.nounId.toString()); if (auction == null) { log.error('[handleAuctionBid] Auction not found for Noun #{}. Hash: {}', [ - nounId, + event.params.nounId.toString(), event.transaction.hash.toHex(), ]); return; @@ -49,7 +50,8 @@ export function handleAuctionBid(event: AuctionBid): void { auction.save(); // Save Bid - let bid = new Bid(event.transaction.hash.toHex()); + const bidId = event.params.nounId.toString().concat('-').concat(event.params.value.toString()); + let bid = new Bid(bidId); bid.bidder = bidder.id; bid.amount = auction.amount; bid.noun = auction.noun; @@ -60,6 +62,21 @@ export function handleAuctionBid(event: AuctionBid): void { bid.save(); } +export function handleAuctionBidWithClientId(event: AuctionBidWithClientId): void { + const bidId = event.params.nounId.toString().concat('-').concat(event.params.value.toString()); + const bid = Bid.load(bidId); + if (bid == null) { + log.error('[handleAuctionBidWithClientId] Bid not found for Noun #{}. Hash: {}', [ + event.params.nounId.toString(), + event.transaction.hash.toHex(), + ]); + return; + } + + bid.clientId = event.params.clientId.toI32(); + bid.save(); +} + export function handleAuctionExtended(event: AuctionExtended): void { let nounId = event.params.nounId.toString(); @@ -78,7 +95,6 @@ export function handleAuctionExtended(event: AuctionExtended): void { export function handleAuctionSettled(event: AuctionSettled): void { let nounId = event.params.nounId.toString(); - let auction = Auction.load(nounId); if (auction == null) { log.error('[handleAuctionSettled] Auction not found for Noun #{}. Hash: {}', [ @@ -91,3 +107,18 @@ export function handleAuctionSettled(event: AuctionSettled): void { auction.settled = true; auction.save(); } + +export function handleAuctionSettledWithClientId(event: AuctionSettledWithClientId): void { + let nounId = event.params.nounId.toString(); + let auction = Auction.load(nounId); + if (auction == null) { + log.error('[handleAuctionSettled] Auction not found for Noun #{}. Hash: {}', [ + nounId, + event.transaction.hash.toHex(), + ]); + return; + } + + auction.clientId = event.params.clientId.toI32(); + auction.save(); +} diff --git a/packages/nouns-subgraph/src/nouns-dao.ts b/packages/nouns-subgraph/src/nouns-dao.ts index 7d8c523111..98423cae20 100644 --- a/packages/nouns-subgraph/src/nouns-dao.ts +++ b/packages/nouns-subgraph/src/nouns-dao.ts @@ -1,5 +1,7 @@ -import { Bytes, log, ethereum, store, BigInt } from '@graphprotocol/graph-ts'; +import { Bytes, log, ethereum, store, BigInt, Address } from '@graphprotocol/graph-ts'; import { + NounsDAO, + ProposalCreated, ProposalCreatedWithRequirements, ProposalCreatedWithRequirements1, ProposalCanceled, @@ -22,6 +24,10 @@ import { ProposalCreatedOnTimelockV1, VoteSnapshotBlockSwitchProposalIdSet, } from './types/NounsDAO/NounsDAO'; +import { + VoteCastWithClientId, + ProposalCreatedWithRequirements1 as ProposalCreatedWithRequirementsV4, +} from './types/NounsDAOV4/NounsDAOV4'; import { getOrCreateDelegate, getOrCreateProposal, @@ -56,60 +62,95 @@ import { ProposalCandidateContent, } from './types/schema'; +export function handleProposalCreated(event: ProposalCreated): void { + let proposal = getOrCreateProposal(event.params.id.toString()); + let proposerResult = getOrCreateDelegateWithNullOption(event.params.proposer.toHexString()); + + proposal.proposer = proposerResult.entity!.id; + proposal.targets = changetype(event.params.targets); + proposal.values = event.params.values; + proposal.signatures = event.params.signatures; + proposal.calldatas = event.params.calldatas; + proposal.createdTimestamp = event.block.timestamp; + proposal.createdBlock = event.block.number; + proposal.lastUpdatedTimestamp = event.block.timestamp; + proposal.lastUpdatedBlock = event.block.number; + proposal.createdTransactionHash = event.transaction.hash; + proposal.startBlock = event.params.startBlock; + proposal.endBlock = event.params.endBlock; + proposal.forVotes = BIGINT_ZERO; + proposal.againstVotes = BIGINT_ZERO; + proposal.abstainVotes = BIGINT_ZERO; + let desc = event.params.description.split('\\n').join('\n'); + proposal.description = desc; + proposal.title = extractTitle(desc); + proposal.status = event.block.number >= proposal.startBlock! ? STATUS_ACTIVE : STATUS_PENDING; + proposal.objectionPeriodEndBlock = BIGINT_ZERO; + + const governance = getGovernanceEntity(); + proposal.totalSupply = governance.totalTokenHolders; + const nounsDAO = NounsDAO.bind(event.address); + let adjustedSupplyResult = nounsDAO.try_adjustedTotalSupply(); + + if (!adjustedSupplyResult.reverted) { + proposal.adjustedTotalSupply = adjustedSupplyResult.value; + } else { + proposal.adjustedTotalSupply = proposal.totalSupply; + } + + if ( + governance.voteSnapshotBlockSwitchProposalId.equals(BIGINT_ZERO) || + BigInt.fromString(proposal.id).lt(governance.voteSnapshotBlockSwitchProposalId) + ) { + proposal.voteSnapshotBlock = proposal.createdBlock; + } else { + proposal.voteSnapshotBlock = proposal.startBlock; + } + + const dynamicQuorum = getOrCreateDynamicQuorumParams(); + proposal.minQuorumVotesBPS = dynamicQuorum.minQuorumVotesBPS; + proposal.maxQuorumVotesBPS = dynamicQuorum.maxQuorumVotesBPS; + proposal.quorumCoefficient = dynamicQuorum.quorumCoefficient; + + proposal.clientId = 0; + proposal.save(); + + captureProposalVersion( + event.transaction.hash.toHexString(), + event.logIndex.toString(), + proposal, + false, + ); +} + export function handleProposalCreatedWithRequirements( event: ProposalCreatedWithRequirements1, ): void { - handleProposalCreated(ParsedProposalV3.fromV1Event(event)); + saveProposalExtraDetails(ParsedProposalV3.fromV1Event(event)); } export function handleProposalCreatedWithRequirementsV3( event: ProposalCreatedWithRequirements, ): void { - handleProposalCreated(ParsedProposalV3.fromV3Event(event)); + saveProposalExtraDetails(ParsedProposalV3.fromV3Event(event)); } -export function handleProposalCreatedOnTimelockV1(event: ProposalCreatedOnTimelockV1): void { - let proposal = getOrCreateProposal(event.params.id.toString()); - proposal.onTimelockV1 = true; - proposal.save(); +export function handleProposalCreatedWithRequirementsV4( + event: ProposalCreatedWithRequirementsV4, +): void { + saveProposalExtraDetails(ParsedProposalV3.fromV4Event(event)); } -export function handleProposalCreated(parsedProposal: ParsedProposalV3): void { +export function saveProposalExtraDetails(parsedProposal: ParsedProposalV3): void { let proposal = getOrCreateProposal(parsedProposal.id); - let proposerResult = getOrCreateDelegateWithNullOption(parsedProposal.proposer); - - // Check if the proposer was a delegate already accounted for, if not we should log an error - // since it shouldn't be possible for a delegate to propose anything without first being 'created' - if (proposerResult.created && parsedProposal.signers.length == 0) { - log.error('Delegate {} not found on ProposalCreated. tx_hash: {}', [ - parsedProposal.proposer, - parsedProposal.txHash, - ]); - } - // Create it anyway, which supports V3 cases of proposers not having any Nouns - proposal.proposer = proposerResult.entity!.id; - proposal.targets = parsedProposal.targets; - proposal.values = parsedProposal.values; - proposal.signatures = parsedProposal.signatures; - proposal.calldatas = parsedProposal.calldatas; - proposal.createdTimestamp = parsedProposal.createdTimestamp; - proposal.createdBlock = parsedProposal.createdBlock; - proposal.lastUpdatedTimestamp = parsedProposal.createdTimestamp; - proposal.lastUpdatedBlock = parsedProposal.createdBlock; - proposal.createdTransactionHash = parsedProposal.createdTransactionHash; - proposal.startBlock = parsedProposal.startBlock; - proposal.endBlock = parsedProposal.endBlock; - proposal.updatePeriodEndBlock = parsedProposal.updatePeriodEndBlock; - proposal.proposalThreshold = parsedProposal.proposalThreshold; - proposal.quorumVotes = parsedProposal.quorumVotes; proposal.forVotes = BIGINT_ZERO; proposal.againstVotes = BIGINT_ZERO; proposal.abstainVotes = BIGINT_ZERO; - proposal.description = parsedProposal.description; - proposal.title = parsedProposal.title; - proposal.status = parsedProposal.status; - proposal.objectionPeriodEndBlock = BIGINT_ZERO; + + proposal.updatePeriodEndBlock = parsedProposal.updatePeriodEndBlock; + proposal.proposalThreshold = parsedProposal.proposalThreshold; + proposal.quorumVotes = parsedProposal.quorumVotes; const signerDelegates = new Array(parsedProposal.signers.length); for (let i = 0; i < parsedProposal.signers.length; i++) { @@ -124,34 +165,15 @@ export function handleProposalCreated(parsedProposal: ParsedProposalV3): void { signerDelegates[i] = signerDelegateResult.entity!.id; } proposal.signers = signerDelegates; - - // Storing state for dynamic quorum calculations - // Doing these for V1 props as well to avoid making these fields optional + avoid missing required field warnings - const governance = getGovernanceEntity(); - proposal.totalSupply = governance.totalTokenHolders; - if (parsedProposal.adjustedTotalSupply.equals(BIGINT_ZERO)) { - proposal.adjustedTotalSupply = proposal.totalSupply; - } else { - proposal.adjustedTotalSupply = parsedProposal.adjustedTotalSupply; - } - - if ( - governance.voteSnapshotBlockSwitchProposalId.equals(BIGINT_ZERO) || - BigInt.fromString(proposal.id).lt(governance.voteSnapshotBlockSwitchProposalId) - ) { - proposal.voteSnapshotBlock = proposal.createdBlock; - } else { - proposal.voteSnapshotBlock = proposal.startBlock; - } - - const dynamicQuorum = getOrCreateDynamicQuorumParams(); - proposal.minQuorumVotesBPS = dynamicQuorum.minQuorumVotesBPS; - proposal.maxQuorumVotesBPS = dynamicQuorum.maxQuorumVotesBPS; - proposal.quorumCoefficient = dynamicQuorum.quorumCoefficient; + proposal.clientId = parsedProposal.clientId.toI32(); proposal.save(); +} - captureProposalVersion(parsedProposal.txHash, parsedProposal.logIndex, proposal, false); +export function handleProposalCreatedOnTimelockV1(event: ProposalCreatedOnTimelockV1): void { + let proposal = getOrCreateProposal(event.params.id.toString()); + proposal.onTimelockV1 = true; + proposal.save(); } export function handleProposalUpdated(event: ProposalUpdated): void { @@ -165,7 +187,7 @@ export function handleProposalUpdated(event: ProposalUpdated): void { proposal.signatures = event.params.signatures; proposal.calldatas = event.params.calldatas; proposal.description = event.params.description.split('\\n').join('\n'); - proposal.title = extractTitle(proposal.description); + proposal.title = extractTitle(proposal.description!); proposal.save(); captureProposalVersion( @@ -183,7 +205,7 @@ export function handleProposalDescriptionUpdated(event: ProposalDescriptionUpdat proposal.lastUpdatedTimestamp = event.block.timestamp; proposal.lastUpdatedBlock = event.block.number; proposal.description = event.params.description.split('\\n').join('\n'); - proposal.title = extractTitle(proposal.description); + proposal.title = extractTitle(proposal.description!); proposal.save(); captureProposalVersion( @@ -263,24 +285,13 @@ export function handleProposalExecuted(event: ProposalExecuted): void { export function handleVoteCast(event: VoteCast): void { let proposal = getOrCreateProposal(event.params.proposalId.toString()); - let voteId = event.params.voter - .toHexString() - .concat('-') - .concat(event.params.proposalId.toString()); + let voteId = generateVoteId(event.params.voter, event.params.proposalId); let vote = getOrCreateVote(voteId); - let voterResult = getOrCreateDelegateWithNullOption(event.params.voter.toHexString()); - - // Check if the voter was a delegate already accounted for, if not we should log an error - // since it shouldn't be possible for a delegate to vote without first being 'created' - if (voterResult.created) { - log.error('Delegate {} not found on VoteCast. tx_hash: {}', [ - event.params.voter.toHexString(), - event.transaction.hash.toHexString(), - ]); - } - // Create it anyway since we will want to account for this event data, even though it should've never happened + // Voter can be created here and not earlier because we support zero-voting-balance votes. + let voterResult = getOrCreateDelegateWithNullOption(event.params.voter.toHexString()); const voter = voterResult.entity!; + vote.proposal = proposal.id; vote.voter = voter.id; vote.votesRaw = event.params.votes; @@ -308,15 +319,15 @@ export function handleVoteCast(event: VoteCast): void { const dqParams = getOrCreateDynamicQuorumParams(); const usingDynamicQuorum = dqParams.dynamicQuorumStartBlock !== null && - dqParams.dynamicQuorumStartBlock!.lt(proposal.createdBlock); + dqParams.dynamicQuorumStartBlock!.lt(proposal.createdBlock!); if (usingDynamicQuorum) { proposal.quorumVotes = dynamicQuorumVotes( proposal.againstVotes, - proposal.adjustedTotalSupply, + proposal.adjustedTotalSupply!, proposal.minQuorumVotesBPS, proposal.maxQuorumVotesBPS, - proposal.quorumCoefficient, + proposal.quorumCoefficient!, ); } @@ -326,6 +337,13 @@ export function handleVoteCast(event: VoteCast): void { proposal.save(); } +export function handleVoteCastWithClientId(event: VoteCastWithClientId): void { + let voteId = generateVoteId(event.params.voter, event.params.proposalId); + let vote = getOrCreateVote(voteId); + vote.clientId = event.params.clientId.toI32(); + vote.save(); +} + export function handleMinQuorumVotesBPSSet(event: MinQuorumVotesBPSSet): void { const params = getOrCreateDynamicQuorumParams(event.block.number); params.minQuorumVotesBPS = event.params.newMinQuorumVotesBPS; @@ -379,14 +397,14 @@ function captureProposalVersion( const versionId = txHash.concat('-').concat(logIndex); const previousVersion = getOrCreateProposalVersion(versionId); previousVersion.proposal = proposal.id; - previousVersion.createdBlock = proposal.lastUpdatedBlock; - previousVersion.createdAt = proposal.lastUpdatedTimestamp; + previousVersion.createdBlock = proposal.lastUpdatedBlock!; + previousVersion.createdAt = proposal.lastUpdatedTimestamp!; previousVersion.targets = proposal.targets; previousVersion.values = proposal.values; previousVersion.signatures = proposal.signatures; previousVersion.calldatas = proposal.calldatas; - previousVersion.title = proposal.title; - previousVersion.description = proposal.description; + previousVersion.title = proposal.title!; + previousVersion.description = proposal.description!; previousVersion.updateMessage = updateMessage; previousVersion.save(); @@ -513,3 +531,7 @@ export function handleVoteSnapshotBlockSwitchProposalIdSet( function genericUniqueId(event: ethereum.Event): string { return event.transaction.hash.toHexString().concat('-').concat(event.logIndex.toString()); } + +function generateVoteId(voter: Address, proposalId: BigInt): string { + return voter.toHexString().concat('-').concat(proposalId.toString()); +} diff --git a/packages/nouns-subgraph/src/utils/helpers.ts b/packages/nouns-subgraph/src/utils/helpers.ts index 2363c81497..0868a9e53a 100644 --- a/packages/nouns-subgraph/src/utils/helpers.ts +++ b/packages/nouns-subgraph/src/utils/helpers.ts @@ -92,6 +92,7 @@ export function getOrCreateVote( if (vote == null && createIfNotFound) { vote = new Vote(id); + vote.clientId = 0; if (save) { vote.save(); @@ -253,7 +254,7 @@ function keccak256Bytes(bytes: Bytes): Bytes { } /** - * encodes the proposal content as done in `NounsDAOV3Proposals.calcProposalEncodeData` + * encodes the proposal content as done in `NounsDAOProposals.calcProposalEncodeData` * and hashes it with keccak256 */ export function calcEncodedProposalHash(proposal: Proposal, isUpdate: boolean): Bytes { @@ -281,12 +282,12 @@ export function calcEncodedProposalHash(proposal: Proposal, isUpdate: boolean): } let params = new ethereum.Tuple(); - params.push(ethereum.Value.fromAddress(Address.fromString(proposal.proposer))); + params.push(ethereum.Value.fromAddress(Address.fromString(proposal.proposer!))); params.push(ethereum.Value.fromFixedBytes(keccak256Bytes(targetsConcat))); params.push(ethereum.Value.fromFixedBytes(keccak256Bytes(valuesConcat))); params.push(ethereum.Value.fromFixedBytes(keccak256Bytes(signatureHashes))); params.push(ethereum.Value.fromFixedBytes(keccak256Bytes(calldatasHashes))); - params.push(ethereum.Value.fromFixedBytes(keccak256Bytes(Bytes.fromUTF8(proposal.description)))); + params.push(ethereum.Value.fromFixedBytes(keccak256Bytes(Bytes.fromUTF8(proposal.description!)))); let proposalEncodeData = ethereum.encode(ethereum.Value.fromTuple(params))!; diff --git a/packages/nouns-subgraph/subgraph.yaml.mustache b/packages/nouns-subgraph/subgraph.yaml.mustache index 6a5ab1465f..2256604a15 100644 --- a/packages/nouns-subgraph/subgraph.yaml.mustache +++ b/packages/nouns-subgraph/subgraph.yaml.mustache @@ -33,6 +33,31 @@ dataSources: handler: handleAuctionExtended - event: AuctionSettled(indexed uint256,address,uint256) handler: handleAuctionSettled + - kind: ethereum/contract + name: NounsAuctionHouseV2 + network: {{network}} + source: + address: '{{nounsAuctionHouse.address}}' + abi: NounsAuctionHouseV2 + startBlock: {{nounsAuctionHouse.startBlock}} + mapping: + kind: ethereum/events + apiVersion: 0.0.6 + language: wasm/assemblyscript + file: ./src/nouns-auction-house.ts + entities: + - Account + - Auction + - Bid + - Noun + abis: + - name: NounsAuctionHouseV2 + file: ../nouns-contracts/abi/contracts/NounsAuctionHouseV2.json + eventHandlers: + - event: AuctionBidWithClientId(indexed uint256,uint256,indexed uint32) + handler: handleAuctionBidWithClientId + - event: AuctionSettledWithClientId(indexed uint256,indexed uint32) + handler: handleAuctionSettledWithClientId - kind: ethereum/contract name: NounsToken network: {{network}} @@ -86,6 +111,8 @@ dataSources: - name: NounsDAO file: ../nouns-contracts/abi/contracts/governance/NounsDAOLogicV3.sol/NounsDAOLogicV3.json eventHandlers: + - event: ProposalCreated(uint256,address,address[],uint256[],string[],bytes[],uint256,uint256,string) + handler: handleProposalCreated - event: ProposalCreatedWithRequirements(uint256,address,address[],uint256[],string[],bytes[],uint256,uint256,uint256,uint256,string) handler: handleProposalCreatedWithRequirements - event: ProposalCreatedWithRequirements(uint256,address,address[],address[],uint256[],string[],bytes[],uint256,uint256,uint256,uint256,uint256,string) @@ -128,6 +155,33 @@ dataSources: handler: handleJoinFork - event: VoteSnapshotBlockSwitchProposalIdSet(uint256,uint256) handler: handleVoteSnapshotBlockSwitchProposalIdSet + - kind: ethereum/contract + name: NounsDAOV4 + network: {{network}} + source: + address: '{{nounsDAO.address}}' + abi: NounsDAOV4 + startBlock: {{nounsDAO.startBlock}} + mapping: + kind: ethereum/events + apiVersion: 0.0.6 + language: wasm/assemblyscript + file: ./src/nouns-dao.ts + entities: + - Account + - Delegate + - Proposal + - Vote + - Governance + - ProposalCandidateSignature + abis: + - name: NounsDAOV4 + file: ../nouns-contracts/abi/contracts/governance/NounsDAOLogicV4.json + eventHandlers: + - event: ProposalCreatedWithRequirements(uint256,address[],uint256,uint256,uint256,indexed uint32) + handler: handleProposalCreatedWithRequirementsV4 + - event: VoteCastWithClientId(indexed address,indexed uint256,indexed uint32) + handler: handleVoteCastWithClientId - kind: ethereum/contract name: NounsDAOData network: {{network}} diff --git a/packages/nouns-subgraph/tests/nouns-dao.test.ts b/packages/nouns-subgraph/tests/nouns-dao.test.ts index 53936c6f54..7d0ff2c43e 100644 --- a/packages/nouns-subgraph/tests/nouns-dao.test.ts +++ b/packages/nouns-subgraph/tests/nouns-dao.test.ts @@ -3,17 +3,14 @@ import { clearStore, test, describe, - beforeAll, afterAll, beforeEach, afterEach, createMockedFunction, - newMockEvent, } from 'matchstick-as/assembly/index'; import { Address, BigInt, Bytes, ethereum } from '@graphprotocol/graph-ts'; import { EscrowDeposit, EscrowedNoun, Proposal, ProposalVersion } from '../src/types/schema'; import { - handleProposalCreatedWithRequirements, handleVoteCast, handleMinQuorumVotesBPSSet, handleMaxQuorumVotesBPSSet, @@ -29,6 +26,7 @@ import { handleProposalVetoed, handleProposalExecuted, handleProposalQueued, + saveProposalExtraDetails, } from '../src/nouns-dao'; import { createProposalCreatedWithRequirementsEventV1, @@ -49,12 +47,13 @@ import { createProposalVetoedEvent, createProposalExecutedEvent, createProposalQueuedEvent, + createProposalCreatedEvent, + ProposalCreatedData, } from './utils'; import { BIGINT_10K, BIGINT_ONE, BIGINT_ZERO, - STATUS_ACTIVE, STATUS_CANCELLED, STATUS_EXECUTED, STATUS_PENDING, @@ -71,7 +70,6 @@ import { extractTitle, ParsedProposalV3 } from '../src/custom-types/ParsedPropos const SOME_ADDRESS = '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266'; const proposerWithDelegate = Address.fromString('0x0000000000000000000000000000000000000001'); -const proposerWithNoDelegate = Address.fromString('0x0000000000000000000000000000000000000002'); const signerWithDelegate = Address.fromString('0x0000000000000000000000000000000000000003'); const signerWithNoDelegate = Address.fromString('0x0000000000000000000000000000000000000004'); @@ -92,175 +90,94 @@ describe('nouns-dao', () => { delegate.delegatedVotes = BIGINT_ONE; delegate.delegatedVotesRaw = BIGINT_ONE; delegate.save(); + + createMockedFunction( + Address.fromString(SOME_ADDRESS), + 'adjustedTotalSupply', + 'adjustedTotalSupply():(uint256)', + ).returns([ethereum.Value.fromUnsignedBigInt(BigInt.fromI32(600))]); }); describe('handleProposalCreated', () => { - describe('with signers', () => { - beforeAll(() => { - const delegate = getOrCreateDelegate(signerWithDelegate.toHexString()); - delegate.tokenHoldersRepresentedAmount = 1; - delegate.delegatedVotes = BIGINT_ONE; - delegate.delegatedVotesRaw = BIGINT_ONE; - delegate.save(); - - createMockedFunction( - newMockEvent().address, - 'adjustedTotalSupply', - 'adjustedTotalSupply():(uint256)', - ).returns([ethereum.Value.fromI32(0)]); - }); - - afterAll(() => { - clearStore(); - }); - - test('uses existing delegates when they exist, and creates new ones when they are missing', () => { - const proposalEvent = new ParsedProposalV3(); - proposalEvent.id = '1'; - proposalEvent.proposer = proposerWithDelegate.toHexString(); - proposalEvent.signers = [ - signerWithDelegate.toHexString(), - signerWithNoDelegate.toHexString(), - ]; - - // 2 delegates because one is the proposer and the second is the signer with a delegate - assert.entityCount('Delegate', 2); - - handleProposalCreated(proposalEvent); - assert.entityCount('Proposal', 1); - assert.entityCount('Delegate', 3); - - const proposal = Proposal.load('1')!; - assert.stringEquals(proposal.proposer, proposalEvent.proposer); - assert.stringEquals(proposal.signers![0], signerWithDelegate.toHexString()); - assert.stringEquals(proposal.signers![1], signerWithNoDelegate.toHexString()); - - // The delegate that already existed has a votes balance - assert.fieldEquals('Delegate', proposal.signers![0], 'tokenHoldersRepresentedAmount', '1'); - assert.fieldEquals('Delegate', proposal.signers![0], 'delegatedVotes', '1'); - assert.fieldEquals('Delegate', proposal.signers![0], 'delegatedVotesRaw', '1'); - - // The delegate that was created on the fly has no votes - assert.fieldEquals('Delegate', proposal.signers![1], 'tokenHoldersRepresentedAmount', '0'); - assert.fieldEquals('Delegate', proposal.signers![1], 'delegatedVotes', '0'); - assert.fieldEquals('Delegate', proposal.signers![1], 'delegatedVotesRaw', '0'); - }); - }); - - describe('single proposer', () => { - test('uses an existing delegate when it is there', () => { - const proposalEvent = new ParsedProposalV3(); - proposalEvent.id = '1'; - proposalEvent.proposer = proposerWithDelegate.toHexString(); - assert.entityCount('Delegate', 1); - - handleProposalCreated(proposalEvent); - - assert.entityCount('Proposal', 1); - assert.entityCount('Delegate', 1); - assert.fieldEquals('Proposal', '1', 'proposer', proposalEvent.proposer); - assert.fieldEquals( - 'Delegate', - proposalEvent.proposer, - 'tokenHoldersRepresentedAmount', - '1', - ); - assert.fieldEquals('Delegate', proposalEvent.proposer, 'delegatedVotes', '1'); - assert.fieldEquals('Delegate', proposalEvent.proposer, 'delegatedVotesRaw', '1'); - }); - - test('creates a delegate if the proposer was never seen before', () => { - const proposalEvent = new ParsedProposalV3(); - proposalEvent.id = '1'; - proposalEvent.proposer = proposerWithNoDelegate.toHexString(); - assert.entityCount('Delegate', 1); - - handleProposalCreated(proposalEvent); - - assert.entityCount('Proposal', 1); - assert.entityCount('Delegate', 2); - assert.fieldEquals('Proposal', '1', 'proposer', proposalEvent.proposer); - assert.fieldEquals( - 'Delegate', - proposalEvent.proposer, - 'tokenHoldersRepresentedAmount', - '0', - ); - assert.fieldEquals('Delegate', proposalEvent.proposer, 'delegatedVotes', '0'); - assert.fieldEquals('Delegate', proposalEvent.proposer, 'delegatedVotesRaw', '0'); - }); - }); - describe('field setting', () => { test('copies values from ParsedProposalV3 and saves a ProposalVersion', () => { - const proposalEvent = new ParsedProposalV3(); - proposalEvent.id = '42'; - proposalEvent.proposer = proposerWithDelegate.toHexString(); - proposalEvent.targets = changetype([Address.fromString(SOME_ADDRESS)]); - proposalEvent.values = [BigInt.fromI32(123)]; - proposalEvent.signatures = ['some signature']; - proposalEvent.calldatas = [Bytes.fromI32(312)]; - proposalEvent.createdTimestamp = BigInt.fromI32(946684800); - proposalEvent.createdBlock = BigInt.fromI32(15537394); - proposalEvent.createdTransactionHash = Bytes.fromI32(11); - proposalEvent.startBlock = proposalEvent.createdBlock.plus(BigInt.fromI32(200)); - proposalEvent.endBlock = proposalEvent.createdBlock.plus(BigInt.fromI32(300)); - proposalEvent.updatePeriodEndBlock = proposalEvent.createdBlock.plus(BigInt.fromI32(100)); - proposalEvent.proposalThreshold = BigInt.fromI32(7); - proposalEvent.quorumVotes = BigInt.fromI32(60); - proposalEvent.description = 'some description'; - proposalEvent.title = 'some title'; - proposalEvent.status = STATUS_PENDING; - proposalEvent.txHash = Bytes.fromI32(11223344).toHexString(); - proposalEvent.logIndex = '2'; + const createdBlock = BigInt.fromI32(100); + const propData = new ProposalCreatedData(); + propData.id = BigInt.fromI32(42); + propData.proposer = proposerWithDelegate; + propData.targets = [Address.fromString(SOME_ADDRESS)]; + propData.values = [BigInt.fromI32(123)]; + propData.signatures = ['some signature']; + propData.calldatas = [Bytes.fromI32(312)]; + propData.startBlock = createdBlock.plus(BigInt.fromI32(200)); + propData.endBlock = createdBlock.plus(BigInt.fromI32(300)); + propData.description = 'some description'; + propData.eventBlockNumber = createdBlock; + propData.eventBlockTimestamp = BigInt.fromI32(946684800); + propData.txHash = Bytes.fromI32(11); + propData.logIndex = BigInt.fromI32(2); + propData.address = Address.fromString(SOME_ADDRESS); + + const propExtraDetails = new ParsedProposalV3(); + propExtraDetails.id = propData.id.toString(); + propExtraDetails.updatePeriodEndBlock = BigInt.fromI32(150); + propExtraDetails.proposalThreshold = BigInt.fromI32(42); + propExtraDetails.quorumVotes = BigInt.fromI32(43); + + handleProposalCreated(createProposalCreatedEvent(propData)); + saveProposalExtraDetails(propExtraDetails); - handleProposalCreated(proposalEvent); const proposal = Proposal.load('42')!; - - assert.stringEquals(proposal.proposer, proposalEvent.proposer); - assert.bytesEquals(proposal.targets![0], proposalEvent.targets[0]); - assert.bigIntEquals(proposal.values![0], proposalEvent.values[0]); - assert.stringEquals(proposal.signatures![0], proposalEvent.signatures[0]); - assert.bytesEquals(proposal.calldatas![0], proposalEvent.calldatas[0]); - assert.bigIntEquals(proposal.createdTimestamp, proposalEvent.createdTimestamp); - assert.bigIntEquals(proposal.createdBlock, proposalEvent.createdBlock); - assert.bytesEquals(proposal.createdTransactionHash, proposalEvent.createdTransactionHash); - assert.bigIntEquals(proposal.startBlock, proposalEvent.startBlock); - assert.bigIntEquals(proposal.endBlock, proposalEvent.endBlock); - assert.bigIntEquals(proposal.updatePeriodEndBlock, proposalEvent.updatePeriodEndBlock); - assert.bigIntEquals(proposal.proposalThreshold, proposalEvent.proposalThreshold); - assert.bigIntEquals(proposal.quorumVotes, proposalEvent.quorumVotes); - assert.stringEquals(proposal.description, proposalEvent.description); - assert.stringEquals(proposal.title, proposalEvent.title); - assert.stringEquals(proposal.status, proposalEvent.status); - - const versionId = proposalEvent.txHash.concat('-').concat(proposalEvent.logIndex); + assert.stringEquals(proposal.proposer!, propData.proposer.toHexString()); + assert.bytesEquals(proposal.targets![0], propData.targets[0]); + assert.bigIntEquals(proposal.values![0], propData.values[0]); + assert.stringEquals(proposal.signatures![0], propData.signatures[0]); + assert.bytesEquals(proposal.calldatas![0], propData.calldatas[0]); + assert.bigIntEquals(proposal.createdTimestamp!, propData.eventBlockTimestamp); + assert.bigIntEquals(proposal.createdBlock!, propData.eventBlockNumber); + assert.bytesEquals(proposal.createdTransactionHash!, propData.txHash); + assert.bigIntEquals(proposal.startBlock!, propData.startBlock); + assert.bigIntEquals(proposal.endBlock!, propData.endBlock); + assert.bigIntEquals(proposal.updatePeriodEndBlock!, propExtraDetails.updatePeriodEndBlock); + assert.bigIntEquals(proposal.proposalThreshold!, propExtraDetails.proposalThreshold); + assert.bigIntEquals(proposal.quorumVotes!, propExtraDetails.quorumVotes); + assert.stringEquals(proposal.description!, propData.description); + assert.stringEquals(proposal.title!, extractTitle(propData.description)); + assert.stringEquals(proposal.status!, STATUS_PENDING); + const versionId = propData.txHash + .toHexString() + .concat('-') + .concat(propData.logIndex.toString()); const propVersion = ProposalVersion.load(versionId)!; assert.stringEquals('42', propVersion.proposal); - assert.bigIntEquals(proposalEvent.createdTimestamp, propVersion.createdAt); - assert.bytesEquals(changetype(proposalEvent.targets)[0], propVersion.targets![0]); - assert.bigIntEquals(proposalEvent.values[0], propVersion.values![0]); - assert.stringEquals(proposalEvent.signatures[0], propVersion.signatures![0]); - assert.bytesEquals(proposalEvent.calldatas[0], propVersion.calldatas![0]); - assert.stringEquals(proposalEvent.description, propVersion.description); - assert.stringEquals(proposalEvent.title, propVersion.title); + assert.bigIntEquals(propData.eventBlockTimestamp, propVersion.createdAt); + assert.bytesEquals(changetype(propData.targets)[0], propVersion.targets![0]); + assert.bigIntEquals(propData.values[0], propVersion.values![0]); + assert.stringEquals(propData.signatures[0], propVersion.signatures![0]); + assert.bytesEquals(propData.calldatas[0], propVersion.calldatas![0]); + assert.stringEquals(propData.description, propVersion.description); + assert.stringEquals(extractTitle(propData.description), propVersion.title); assert.stringEquals('', propVersion.updateMessage); }); - test('copies values from governance and dynamic quorum', () => { const governance = getGovernanceEntity(); governance.totalTokenHolders = BigInt.fromI32(601); governance.save(); - const dq = getOrCreateDynamicQuorumParams(); dq.minQuorumVotesBPS = 100; dq.maxQuorumVotesBPS = 150; dq.quorumCoefficient = BIGINT_ONE; dq.save(); - const proposalEvent = new ParsedProposalV3(); - proposalEvent.proposer = proposerWithDelegate.toHexString(); - proposalEvent.id = '43'; + const data = new ProposalCreatedData(); + data.id = BigInt.fromI32(43); + data.proposer = proposerWithDelegate; + data.description = 'some description'; + data.txHash = Bytes.fromI32(11); + data.logIndex = BigInt.fromI32(2); + data.address = Address.fromString(SOME_ADDRESS); + const proposalEvent = createProposalCreatedEvent(data); + handleProposalCreated(proposalEvent); assert.fieldEquals('Proposal', '43', 'totalSupply', '601'); @@ -268,11 +185,16 @@ describe('nouns-dao', () => { assert.fieldEquals('Proposal', '43', 'maxQuorumVotesBPS', '150'); assert.fieldEquals('Proposal', '43', 'quorumCoefficient', '1'); }); - test('sets votes and objection period block to zero', () => { - const proposalEvent = new ParsedProposalV3(); - proposalEvent.proposer = proposerWithDelegate.toHexString(); - proposalEvent.id = '44'; + const data = new ProposalCreatedData(); + data.id = BigInt.fromI32(44); + data.proposer = proposerWithDelegate; + data.description = 'some description'; + data.txHash = Bytes.fromI32(11); + data.logIndex = BigInt.fromI32(2); + data.address = Address.fromString(SOME_ADDRESS); + const proposalEvent = createProposalCreatedEvent(data); + handleProposalCreated(proposalEvent); assert.fieldEquals('Proposal', '44', 'forVotes', '0'); @@ -282,405 +204,391 @@ describe('nouns-dao', () => { }); }); }); +}); - describe('handleVoteCast', () => { - afterEach(() => { - clearStore(); - }); - - test('given V1 prop does not update quorumVotes using dynamic quorum', () => { - getOrCreateDelegate(SOME_ADDRESS); - const totalSupply = BigInt.fromI32(200); - - // Set total supply - const governance = getGovernanceEntity(); - governance.totalTokenHolders = totalSupply; - governance.save(); - - // Save dynamic quorum params - handleAllQuorumParamEvents(1000, 4000, BigInt.fromI32(1_500_000)); - - const dqParams = getOrCreateDynamicQuorumParams(null); - assert.bigIntEquals(BIGINT_ZERO, dqParams.dynamicQuorumStartBlock as BigInt); - - // Create prop with state we need for quorum inputs - // providing block number zero means this prop will look like a V1 prop - // since the DQ events above are simulated to be at block zero - const propEventInput = stubProposalCreatedWithRequirementsEventInput(BIGINT_ZERO); - const newPropEvent = createProposalCreatedWithRequirementsEventV1(propEventInput); - - handleProposalCreatedWithRequirements(newPropEvent); - const propId = BIGINT_ONE; - - let savedProp = Proposal.load(propId.toString()); - assert.bigIntEquals(BIGINT_ONE, savedProp!.quorumVotes); - - const voter = Address.fromString(SOME_ADDRESS); - const support = 0; // against - const votes = BigInt.fromI32(32); - const voteEvent = createVoteCastEvent(voter, propId, support, votes); - - handleVoteCast(voteEvent); - - savedProp = Proposal.load(propId.toString()); - assert.bigIntEquals(BIGINT_ONE, savedProp!.quorumVotes); - }); - - test('updates quorumVotes using dynamic quorum math', () => { - getOrCreateDelegate(SOME_ADDRESS); - const totalSupply = BigInt.fromI32(200); - - // Set total supply - const governance = getGovernanceEntity(); - governance.totalTokenHolders = totalSupply; - governance.save(); - - // Save dynamic quorum params - handleAllQuorumParamEvents(1000, 4000, BigInt.fromI32(1_500_000)); - - const dqParams = getOrCreateDynamicQuorumParams(null); - assert.bigIntEquals(BIGINT_ZERO, dqParams.dynamicQuorumStartBlock as BigInt); - - // Create prop with state we need for quorum inputs - // providing a block number greater than zero means this prop will look like a V2 prop - // since the DQ events above are simulated to be at block zero - const propEventInput = stubProposalCreatedWithRequirementsEventInput(BIGINT_ONE); - const newPropEvent = createProposalCreatedWithRequirementsEventV1(propEventInput); - - handleProposalCreatedWithRequirements(newPropEvent); - - const voter = Address.fromString(SOME_ADDRESS); - const propId = BIGINT_ONE; - const support = 0; // against - const votes = BigInt.fromI32(32); - const voteEvent = createVoteCastEvent(voter, propId, support, votes); - - handleVoteCast(voteEvent); - - const savedProp = Proposal.load(propId.toString()); - - assert.bigIntEquals(BigInt.fromI32(68), savedProp!.quorumVotes); - }); - - test('uses quorum params from prop creation time, not newer params', () => { - getOrCreateDelegate(SOME_ADDRESS); - const totalSupply = BigInt.fromI32(200); - - // Set total supply - const governance = getGovernanceEntity(); - governance.totalTokenHolders = totalSupply; - governance.save(); - - // Save dynamic quorum params - handleAllQuorumParamEvents(1000, 4000, BigInt.fromI32(1_200_000)); - - // Create prop with state we need for quorum inputs - // providing a block number greater than zero means this prop will look like a V2 prop - // since the DQ events above are simulated to be at block zero - const propEventInput = stubProposalCreatedWithRequirementsEventInput(BIGINT_ONE); - const newPropEvent = createProposalCreatedWithRequirementsEventV1(propEventInput); - handleProposalCreatedWithRequirements(newPropEvent); - - handleAllQuorumParamEvents(500, 6000, BigInt.fromI32(3_000_000)); - - const voter = Address.fromString(SOME_ADDRESS); - const propId = BIGINT_ONE; - const support = 0; // against - const votes = BigInt.fromI32(25); - const voteEvent = createVoteCastEvent(voter, propId, support, votes); - - handleVoteCast(voteEvent); - - const savedProp = Proposal.load(propId.toString()); - - assert.bigIntEquals(BigInt.fromI32(50), savedProp!.quorumVotes); - }); +describe('handleVoteCast', () => { + beforeEach(() => { + createMockedFunction( + Address.fromString(SOME_ADDRESS), + 'adjustedTotalSupply', + 'adjustedTotalSupply():(uint256)', + ).returns([ethereum.Value.fromUnsignedBigInt(BigInt.fromI32(200))]); }); - - describe('dynamic quorum config handlers', () => { - afterEach(() => { - clearStore(); - }); - - test('handleMinQuorumVotesBPSSet: saves incoming values', () => { - const event1 = createMinQuorumVotesBPSSetEvent(0, 1); - handleMinQuorumVotesBPSSet(event1); - assert.i32Equals(1, getOrCreateDynamicQuorumParams(BIGINT_ZERO).minQuorumVotesBPS); - - const event2 = createMinQuorumVotesBPSSetEvent(1, 2); - handleMinQuorumVotesBPSSet(event2); - assert.i32Equals(2, getOrCreateDynamicQuorumParams(BIGINT_ZERO).minQuorumVotesBPS); - }); - - test('handleMaxQuorumVotesBPSSet: saves incoming values', () => { - const event1 = createMaxQuorumVotesBPSSetEvent(0, 1000); - handleMaxQuorumVotesBPSSet(event1); - assert.i32Equals(1000, getOrCreateDynamicQuorumParams(BIGINT_ZERO).maxQuorumVotesBPS); - - const event2 = createMaxQuorumVotesBPSSetEvent(1000, 2000); - handleMaxQuorumVotesBPSSet(event2); - assert.i32Equals(2000, getOrCreateDynamicQuorumParams(BIGINT_ZERO).maxQuorumVotesBPS); - }); - - test('handleQuorumCoefficientSet: saves incoming values', () => { - const event1 = createQuorumCoefficientSetEvent(BIGINT_ZERO, BIGINT_ONE); - handleQuorumCoefficientSet(event1); - assert.bigIntEquals( - BIGINT_ONE, - getOrCreateDynamicQuorumParams(BIGINT_ZERO).quorumCoefficient, - ); - - const event2 = createQuorumCoefficientSetEvent(BIGINT_ONE, BIGINT_10K); - handleQuorumCoefficientSet(event2); - assert.bigIntEquals( - BIGINT_10K, - getOrCreateDynamicQuorumParams(BIGINT_ZERO).quorumCoefficient, - ); - }); + afterEach(() => { + clearStore(); }); - describe('handleProposalObjectionPeriodSet', () => { - test('sets the objectionPeriodEndBlock field', () => { - const proposalEvent = new ParsedProposalV3(); - proposalEvent.id = '1'; - proposalEvent.proposer = proposerWithDelegate.toHexString(); - - handleProposalCreated(proposalEvent); - assert.fieldEquals('Proposal', '1', 'objectionPeriodEndBlock', '0'); - - handleProposalObjectionPeriodSet( - createProposalObjectionPeriodSetEvent(BIGINT_ONE, BIGINT_10K), - ); - assert.fieldEquals('Proposal', '1', 'objectionPeriodEndBlock', '10000'); - }); + test('given V1 prop does not update quorumVotes using dynamic quorum', () => { + getOrCreateDelegate(SOME_ADDRESS); + const totalSupply = BigInt.fromI32(200); + + // Set total supply + const governance = getGovernanceEntity(); + governance.totalTokenHolders = totalSupply; + governance.save(); + + // Save dynamic quorum params + handleAllQuorumParamEvents(1000, 4000, BigInt.fromI32(1_500_000)); + + const dqParams = getOrCreateDynamicQuorumParams(null); + assert.bigIntEquals(BIGINT_ZERO, dqParams.dynamicQuorumStartBlock as BigInt); + + // Create prop with state we need for quorum inputs + // providing block number zero means this prop will look like a V1 prop + // since the DQ events above are simulated to be at block zero + const data = new ProposalCreatedData(); + data.id = BIGINT_ONE; + data.proposer = proposerWithDelegate; + data.description = 'some description'; + data.txHash = Bytes.fromI32(11); + data.logIndex = BigInt.fromI32(2); + data.address = Address.fromString(SOME_ADDRESS); + data.eventBlockNumber = BIGINT_ZERO; + handleProposalCreated(createProposalCreatedEvent(data)); + + const propExtraDetails = new ParsedProposalV3(); + propExtraDetails.id = data.id.toString(); + propExtraDetails.updatePeriodEndBlock = BigInt.fromI32(150); + propExtraDetails.proposalThreshold = BigInt.fromI32(42); + propExtraDetails.quorumVotes = BIGINT_ONE; + saveProposalExtraDetails(propExtraDetails); + + let savedProp = Proposal.load(data.id.toString()); + assert.bigIntEquals(BIGINT_ONE, savedProp!.quorumVotes!); + + const voter = Address.fromString(SOME_ADDRESS); + const support = 0; // against + const votes = BigInt.fromI32(32); + const voteEvent = createVoteCastEvent(voter, data.id, support, votes); + handleVoteCast(voteEvent); + + savedProp = Proposal.load(data.id.toString()); + assert.bigIntEquals(BIGINT_ONE, savedProp!.quorumVotes!); }); - describe('Proposal Updated', () => { - beforeEach(() => { - const proposalEvent = new ParsedProposalV3(); - proposalEvent.id = proposalId.toString(); - proposalEvent.proposer = proposerWithDelegate.toHexString(); - proposalEvent.createdTimestamp = updateBlockTimestamp.minus(BIGINT_ONE); - proposalEvent.createdBlock = updateBlockNumber.minus(BIGINT_ONE); - proposalEvent.targets = [signerWithNoDelegate]; - proposalEvent.values = [BigInt.fromI32(987)]; - proposalEvent.signatures = ['first signature']; - proposalEvent.calldatas = [Bytes.fromI32(888)]; - proposalEvent.description = '# Original Title\nOriginal body'; - proposalEvent.title = extractTitle(proposalEvent.description); - - handleProposalCreated(proposalEvent); - }); - - test('handleProposalDescriptionUpdated', () => { - const updateDescription = '# Updated Title\nUpdated body'; - const updateMessage = 'some update message'; + test('updates quorumVotes using dynamic quorum math', () => { + getOrCreateDelegate(SOME_ADDRESS); + const totalSupply = BigInt.fromI32(200); + // Set total supply + const governance = getGovernanceEntity(); + governance.totalTokenHolders = totalSupply; + governance.save(); + // Save dynamic quorum params + handleAllQuorumParamEvents(1000, 4000, BigInt.fromI32(1_500_000)); + const dqParams = getOrCreateDynamicQuorumParams(null); + assert.bigIntEquals(BIGINT_ZERO, dqParams.dynamicQuorumStartBlock as BigInt); + + // Create prop with state we need for quorum inputs + // providing a block number greater than zero means this prop will look like a V2 prop + // since the DQ events above are simulated to be at block zero + const data = new ProposalCreatedData(); + data.id = BIGINT_ONE; + data.proposer = proposerWithDelegate; + data.description = 'some description'; + data.txHash = Bytes.fromI32(11); + data.logIndex = BigInt.fromI32(2); + data.address = Address.fromString(SOME_ADDRESS); + data.eventBlockNumber = BIGINT_ONE; + handleProposalCreated(createProposalCreatedEvent(data)); + + const propExtraDetails = new ParsedProposalV3(); + propExtraDetails.id = data.id.toString(); + propExtraDetails.updatePeriodEndBlock = BigInt.fromI32(150); + propExtraDetails.proposalThreshold = BIGINT_ONE; + propExtraDetails.quorumVotes = BIGINT_ONE; + saveProposalExtraDetails(propExtraDetails); + + const voter = Address.fromString(SOME_ADDRESS); + const propId = BIGINT_ONE; + const support = 0; // against + const votes = BigInt.fromI32(32); + const voteEvent = createVoteCastEvent(voter, propId, support, votes); + handleVoteCast(voteEvent); + const savedProp = Proposal.load(propId.toString()); + assert.bigIntEquals(BigInt.fromI32(68), savedProp!.quorumVotes!); + }); - handleProposalDescriptionUpdated( - createProposalDescriptionUpdatedEvent( - txHash, - logIndex, - updateBlockTimestamp, - updateBlockNumber, - proposalId, - proposerWithDelegate, - updateDescription, - updateMessage, - ), - ); + test('uses quorum params from prop creation time, not newer params', () => { + getOrCreateDelegate(SOME_ADDRESS); + const totalSupply = BigInt.fromI32(200); + // Set total supply + const governance = getGovernanceEntity(); + governance.totalTokenHolders = totalSupply; + governance.save(); + // Save dynamic quorum params + handleAllQuorumParamEvents(1000, 4000, BigInt.fromI32(1_200_000)); + // Create prop with state we need for quorum inputs + // providing a block number greater than zero means this prop will look like a V2 prop + // since the DQ events above are simulated to be at block zero + const data = new ProposalCreatedData(); + data.id = BIGINT_ONE; + data.proposer = proposerWithDelegate; + data.description = 'some description'; + data.txHash = Bytes.fromI32(11); + data.logIndex = BigInt.fromI32(2); + data.address = Address.fromString(SOME_ADDRESS); + data.eventBlockNumber = BIGINT_ONE; + handleProposalCreated(createProposalCreatedEvent(data)); + const propExtraDetails = new ParsedProposalV3(); + propExtraDetails.id = data.id.toString(); + propExtraDetails.updatePeriodEndBlock = BigInt.fromI32(150); + propExtraDetails.proposalThreshold = BIGINT_ONE; + propExtraDetails.quorumVotes = BIGINT_ONE; + saveProposalExtraDetails(propExtraDetails); + + handleAllQuorumParamEvents(500, 6000, BigInt.fromI32(3_000_000)); + const voter = Address.fromString(SOME_ADDRESS); + const propId = BIGINT_ONE; + const support = 0; // against + const votes = BigInt.fromI32(25); + const voteEvent = createVoteCastEvent(voter, propId, support, votes); + handleVoteCast(voteEvent); + const savedProp = Proposal.load(propId.toString()); + assert.bigIntEquals(BigInt.fromI32(50), savedProp!.quorumVotes!); + }); +}); - const proposal = Proposal.load(proposalId.toString())!; - assert.bigIntEquals(updateBlockTimestamp, proposal.lastUpdatedTimestamp); - assert.bigIntEquals(updateBlockNumber, proposal.lastUpdatedBlock); - assert.stringEquals(updateDescription, proposal.description); - assert.stringEquals(extractTitle(updateDescription), proposal.title); - - // check that the original values remained as is - assert.bytesEquals(signerWithNoDelegate, proposal.targets![0]); - assert.bigIntEquals(BigInt.fromI32(987), proposal.values![0]); - assert.stringEquals('first signature', proposal.signatures![0]); - assert.bytesEquals(Bytes.fromI32(888), proposal.calldatas![0]); - - const updatedVersionId = txHash.toHexString().concat('-').concat(logIndex.toString()); - const updatedVersion = ProposalVersion.load(updatedVersionId)!; - assert.stringEquals(proposalId.toString(), updatedVersion.proposal); - assert.bigIntEquals(updateBlockTimestamp, updatedVersion.createdAt); - assert.stringEquals(updateDescription, updatedVersion.description); - assert.stringEquals(extractTitle(updateDescription), updatedVersion.title); - assert.stringEquals(updateMessage, updatedVersion.updateMessage); - - // check that the original values are saved - assert.bytesEquals(signerWithNoDelegate, updatedVersion.targets![0]); - assert.bigIntEquals(BigInt.fromI32(987), updatedVersion.values![0]); - assert.stringEquals('first signature', updatedVersion.signatures![0]); - assert.bytesEquals(Bytes.fromI32(888), updatedVersion.calldatas![0]); - }); +describe('dynamic quorum config handlers', () => { + afterEach(() => { + clearStore(); + }); - test('handleProposalTransactionsUpdated', () => { - const updateTargets = [signerWithDelegate]; - const updateValues = [BigInt.fromI32(321)]; - const updateSignatures = ['update signature']; - const updateCalldatas = [Bytes.fromI32(312)]; - const updateMessage = 'some update message'; + test('handleMinQuorumVotesBPSSet: saves incoming values', () => { + const event1 = createMinQuorumVotesBPSSetEvent(0, 1); + handleMinQuorumVotesBPSSet(event1); + assert.i32Equals(1, getOrCreateDynamicQuorumParams(BIGINT_ZERO).minQuorumVotesBPS); - handleProposalTransactionsUpdated( - createProposalTransactionsUpdatedEvent( - txHash, - logIndex, - updateBlockTimestamp, - updateBlockNumber, - proposalId, - proposerWithDelegate, - updateTargets, - updateValues, - updateSignatures, - updateCalldatas, - updateMessage, - ), - ); + const event2 = createMinQuorumVotesBPSSetEvent(1, 2); + handleMinQuorumVotesBPSSet(event2); + assert.i32Equals(2, getOrCreateDynamicQuorumParams(BIGINT_ZERO).minQuorumVotesBPS); + }); - const proposal = Proposal.load(proposalId.toString())!; - assert.bigIntEquals(updateBlockTimestamp, proposal.lastUpdatedTimestamp); - assert.bigIntEquals(updateBlockNumber, proposal.lastUpdatedBlock); - assert.bytesEquals(changetype(updateTargets)[0], proposal.targets![0]); - assert.bigIntEquals(updateValues[0], proposal.values![0]); - assert.stringEquals(updateSignatures[0], proposal.signatures![0]); - assert.bytesEquals(updateCalldatas[0], proposal.calldatas![0]); - - // check that the original values remained as is - assert.stringEquals('# Original Title\nOriginal body', proposal.description); - assert.stringEquals('Original Title', proposal.title); - - const updatedVersionId = txHash.toHexString().concat('-').concat(logIndex.toString()); - const updatedVersion = ProposalVersion.load(updatedVersionId)!; - assert.stringEquals(proposalId.toString(), updatedVersion.proposal); - assert.bigIntEquals(updateBlockTimestamp, updatedVersion.createdAt); - assert.bytesEquals(changetype(updateTargets)[0], updatedVersion.targets![0]); - assert.bigIntEquals(updateValues[0], updatedVersion.values![0]); - assert.stringEquals(updateSignatures[0], updatedVersion.signatures![0]); - assert.bytesEquals(updateCalldatas[0], updatedVersion.calldatas![0]); - assert.stringEquals(updateMessage, updatedVersion.updateMessage); - - // check that the original values are saved - assert.stringEquals('# Original Title\nOriginal body', updatedVersion.description); - assert.stringEquals('Original Title', updatedVersion.title); - }); + test('handleMaxQuorumVotesBPSSet: saves incoming values', () => { + const event1 = createMaxQuorumVotesBPSSetEvent(0, 1000); + handleMaxQuorumVotesBPSSet(event1); + assert.i32Equals(1000, getOrCreateDynamicQuorumParams(BIGINT_ZERO).maxQuorumVotesBPS); - test('handleProposalUpdated', () => { - const updateTargets = [signerWithDelegate]; - const updateValues = [BigInt.fromI32(321)]; - const updateSignatures = ['update signature']; - const updateCalldatas = [Bytes.fromI32(312)]; - const updateDescription = '# Updated Title\nUpdated body'; - const updateMessage = 'some update message'; + const event2 = createMaxQuorumVotesBPSSetEvent(1000, 2000); + handleMaxQuorumVotesBPSSet(event2); + assert.i32Equals(2000, getOrCreateDynamicQuorumParams(BIGINT_ZERO).maxQuorumVotesBPS); + }); - handleProposalUpdated( - createProposalUpdatedEvent( - txHash, - logIndex, - updateBlockTimestamp, - updateBlockNumber, - proposalId, - proposerWithDelegate, - updateTargets, - updateValues, - updateSignatures, - updateCalldatas, - updateDescription, - updateMessage, - ), - ); + test('handleQuorumCoefficientSet: saves incoming values', () => { + const event1 = createQuorumCoefficientSetEvent(BIGINT_ZERO, BIGINT_ONE); + handleQuorumCoefficientSet(event1); + assert.bigIntEquals(BIGINT_ONE, getOrCreateDynamicQuorumParams(BIGINT_ZERO).quorumCoefficient); - const proposal = Proposal.load(proposalId.toString())!; - assert.bigIntEquals(updateBlockTimestamp, proposal.lastUpdatedTimestamp); - assert.bigIntEquals(updateBlockNumber, proposal.lastUpdatedBlock); - assert.bytesEquals(changetype(updateTargets)[0], proposal.targets![0]); - assert.bigIntEquals(updateValues[0], proposal.values![0]); - assert.stringEquals(updateSignatures[0], proposal.signatures![0]); - assert.bytesEquals(updateCalldatas[0], proposal.calldatas![0]); - assert.stringEquals(updateDescription, proposal.description); - assert.stringEquals(extractTitle(updateDescription), proposal.title); - - const updatedVersionId = txHash.toHexString().concat('-').concat(logIndex.toString()); - const updatedVersion = ProposalVersion.load(updatedVersionId)!; - assert.stringEquals(proposalId.toString(), updatedVersion.proposal); - assert.bigIntEquals(updateBlockTimestamp, updatedVersion.createdAt); - assert.bytesEquals(changetype(updateTargets)[0], updatedVersion.targets![0]); - assert.bigIntEquals(updateValues[0], updatedVersion.values![0]); - assert.stringEquals(updateSignatures[0], updatedVersion.signatures![0]); - assert.bytesEquals(updateCalldatas[0], updatedVersion.calldatas![0]); - assert.stringEquals(updateDescription, updatedVersion.description); - assert.stringEquals(extractTitle(updateDescription), updatedVersion.title); - assert.stringEquals(updateMessage, updatedVersion.updateMessage); - }); + const event2 = createQuorumCoefficientSetEvent(BIGINT_ONE, BIGINT_10K); + handleQuorumCoefficientSet(event2); + assert.bigIntEquals(BIGINT_10K, getOrCreateDynamicQuorumParams(BIGINT_ZERO).quorumCoefficient); }); }); -describe('ParsedProposalV3', () => { - describe('status set to PENDING', () => { - test('fromV1Event', () => { - const propEventInput = stubProposalCreatedWithRequirementsEventInput(BIGINT_ZERO); - const newPropEvent = createProposalCreatedWithRequirementsEventV1(propEventInput); +describe('handleProposalObjectionPeriodSet', () => { + test('sets the objectionPeriodEndBlock field', () => { + const propData = new ProposalCreatedData(); + propData.id = BIGINT_ONE; + propData.proposer = proposerWithDelegate; + propData.targets = [Address.fromString(SOME_ADDRESS)]; + propData.values = [BigInt.fromI32(123)]; + propData.signatures = ['some signature']; + propData.calldatas = [Bytes.fromI32(312)]; + propData.startBlock = BigInt.fromI32(203); + propData.endBlock = BigInt.fromI32(303); + propData.description = 'some description'; + propData.eventBlockNumber = BigInt.fromI32(103); + propData.eventBlockTimestamp = BigInt.fromI32(42); + propData.txHash = Bytes.fromI32(11); + propData.logIndex = BigInt.fromI32(1); + propData.address = Address.fromString(SOME_ADDRESS); + handleProposalCreated(createProposalCreatedEvent(propData)); + + const propExtraDetails = new ParsedProposalV3(); + propExtraDetails.id = propData.id.toString(); + propExtraDetails.updatePeriodEndBlock = BigInt.fromI32(150); + propExtraDetails.proposalThreshold = BIGINT_ONE; + propExtraDetails.quorumVotes = BIGINT_ONE; + saveProposalExtraDetails(propExtraDetails); + + assert.fieldEquals('Proposal', '1', 'objectionPeriodEndBlock', '0'); + + handleProposalObjectionPeriodSet(createProposalObjectionPeriodSetEvent(BIGINT_ONE, BIGINT_10K)); + assert.fieldEquals('Proposal', '1', 'objectionPeriodEndBlock', '10000'); + }); +}); - const parsedProposal = ParsedProposalV3.fromV1Event(newPropEvent); +describe('Proposal Updated', () => { + beforeEach(() => { + const propData = new ProposalCreatedData(); + propData.id = proposalId; + propData.proposer = proposerWithDelegate; + propData.targets = [signerWithNoDelegate]; + propData.values = [BigInt.fromI32(987)]; + propData.signatures = ['first signature']; + propData.calldatas = [Bytes.fromI32(888)]; + propData.startBlock = BigInt.fromI32(203); + propData.endBlock = BigInt.fromI32(303); + propData.description = '# Original Title\nOriginal body'; + propData.eventBlockNumber = updateBlockNumber.minus(BIGINT_ONE); + propData.eventBlockTimestamp = updateBlockTimestamp.minus(BIGINT_ONE); + propData.txHash = Bytes.fromI32(11); + propData.logIndex = BigInt.fromI32(1); + propData.address = Address.fromString(SOME_ADDRESS); + + handleProposalCreated(createProposalCreatedEvent(propData)); + + const propExtraDetails = new ParsedProposalV3(); + propExtraDetails.id = propData.id.toString(); + propExtraDetails.updatePeriodEndBlock = BigInt.fromI32(150); + propExtraDetails.proposalThreshold = BIGINT_ONE; + propExtraDetails.quorumVotes = BIGINT_ONE; + saveProposalExtraDetails(propExtraDetails); + }); - assert.stringEquals(parsedProposal.status, STATUS_PENDING); - }); - test('fromV3Event', () => { - const propEventInput = stubProposalCreatedWithRequirementsEventInput(BIGINT_ZERO); - const newPropEvent = createProposalCreatedWithRequirementsEventV3(propEventInput); + test('handleProposalDescriptionUpdated', () => { + const updateDescription = '# Updated Title\nUpdated body'; + const updateMessage = 'some update message'; - const parsedProposal = ParsedProposalV3.fromV3Event(newPropEvent); + handleProposalDescriptionUpdated( + createProposalDescriptionUpdatedEvent( + txHash, + logIndex, + updateBlockTimestamp, + updateBlockNumber, + proposalId, + proposerWithDelegate, + updateDescription, + updateMessage, + ), + ); - assert.stringEquals(parsedProposal.status, STATUS_PENDING); - }); + const proposal = Proposal.load(proposalId.toString())!; + assert.bigIntEquals(updateBlockTimestamp, proposal.lastUpdatedTimestamp!); + assert.bigIntEquals(updateBlockNumber, proposal.lastUpdatedBlock!); + assert.stringEquals(updateDescription, proposal.description!); + assert.stringEquals(extractTitle(updateDescription), proposal.title!); + + // check that the original values remained as is + assert.bytesEquals(signerWithNoDelegate, proposal.targets![0]); + assert.bigIntEquals(BigInt.fromI32(987), proposal.values![0]); + assert.stringEquals('first signature', proposal.signatures![0]); + assert.bytesEquals(Bytes.fromI32(888), proposal.calldatas![0]); + + const updatedVersionId = txHash.toHexString().concat('-').concat(logIndex.toString()); + const updatedVersion = ProposalVersion.load(updatedVersionId)!; + assert.stringEquals(proposalId.toString(), updatedVersion.proposal); + assert.bigIntEquals(updateBlockTimestamp, updatedVersion.createdAt); + assert.stringEquals(updateDescription, updatedVersion.description); + assert.stringEquals(extractTitle(updateDescription), updatedVersion.title); + assert.stringEquals(updateMessage, updatedVersion.updateMessage); + + // check that the original values are saved + assert.bytesEquals(signerWithNoDelegate, updatedVersion.targets![0]); + assert.bigIntEquals(BigInt.fromI32(987), updatedVersion.values![0]); + assert.stringEquals('first signature', updatedVersion.signatures![0]); + assert.bytesEquals(Bytes.fromI32(888), updatedVersion.calldatas![0]); }); - describe('status set to ACTIVE', () => { - test('fromV1Event', () => { - const propEventInput = stubProposalCreatedWithRequirementsEventInput(BIGINT_ZERO); - propEventInput.eventBlockNumber = BigInt.fromI32(42); - propEventInput.startBlock = BigInt.fromI32(41); - const newPropEvent = createProposalCreatedWithRequirementsEventV1(propEventInput); - const parsedProposal = ParsedProposalV3.fromV1Event(newPropEvent); + test('handleProposalTransactionsUpdated', () => { + const updateTargets = [signerWithDelegate]; + const updateValues = [BigInt.fromI32(321)]; + const updateSignatures = ['update signature']; + const updateCalldatas = [Bytes.fromI32(312)]; + const updateMessage = 'some update message'; - assert.stringEquals(parsedProposal.status, STATUS_ACTIVE); - }); - test('fromV3Event', () => { - const propEventInput = stubProposalCreatedWithRequirementsEventInput(BIGINT_ZERO); - propEventInput.eventBlockNumber = BigInt.fromI32(42); - propEventInput.startBlock = BigInt.fromI32(41); - const newPropEvent = createProposalCreatedWithRequirementsEventV3(propEventInput); - - const parsedProposal = ParsedProposalV3.fromV3Event(newPropEvent); + handleProposalTransactionsUpdated( + createProposalTransactionsUpdatedEvent( + txHash, + logIndex, + updateBlockTimestamp, + updateBlockNumber, + proposalId, + proposerWithDelegate, + updateTargets, + updateValues, + updateSignatures, + updateCalldatas, + updateMessage, + ), + ); - assert.stringEquals(parsedProposal.status, STATUS_ACTIVE); - }); + const proposal = Proposal.load(proposalId.toString())!; + assert.bigIntEquals(updateBlockTimestamp, proposal.lastUpdatedTimestamp!); + assert.bigIntEquals(updateBlockNumber, proposal.lastUpdatedBlock!); + assert.bytesEquals(changetype(updateTargets)[0], proposal.targets![0]); + assert.bigIntEquals(updateValues[0], proposal.values![0]); + assert.stringEquals(updateSignatures[0], proposal.signatures![0]); + assert.bytesEquals(updateCalldatas[0], proposal.calldatas![0]); + + // check that the original values remained as is + assert.stringEquals('# Original Title\nOriginal body', proposal.description!); + assert.stringEquals('Original Title', proposal.title!); + + const updatedVersionId = txHash.toHexString().concat('-').concat(logIndex.toString()); + const updatedVersion = ProposalVersion.load(updatedVersionId)!; + assert.stringEquals(proposalId.toString(), updatedVersion.proposal); + assert.bigIntEquals(updateBlockTimestamp, updatedVersion.createdAt); + assert.bytesEquals(changetype(updateTargets)[0], updatedVersion.targets![0]); + assert.bigIntEquals(updateValues[0], updatedVersion.values![0]); + assert.stringEquals(updateSignatures[0], updatedVersion.signatures![0]); + assert.bytesEquals(updateCalldatas[0], updatedVersion.calldatas![0]); + assert.stringEquals(updateMessage, updatedVersion.updateMessage); + + // check that the original values are saved + assert.stringEquals('# Original Title\nOriginal body', updatedVersion.description); + assert.stringEquals('Original Title', updatedVersion.title); }); - describe('extracts title', () => { - test('fromV1Event', () => { - const propEventInput = stubProposalCreatedWithRequirementsEventInput(); - propEventInput.description = '# Title text\nBody text'; - const newPropEvent = createProposalCreatedWithRequirementsEventV1(propEventInput); - - const parsedProposal = ParsedProposalV3.fromV1Event(newPropEvent); - - assert.stringEquals(parsedProposal.title, 'Title text'); - assert.stringEquals(parsedProposal.description, propEventInput.description); - }); - test('fromV3Event', () => { - const propEventInput = stubProposalCreatedWithRequirementsEventInput(); - propEventInput.description = '# Title text\nBody text'; - const newPropEvent = createProposalCreatedWithRequirementsEventV3(propEventInput); + test('handleProposalUpdated', () => { + const updateTargets = [signerWithDelegate]; + const updateValues = [BigInt.fromI32(321)]; + const updateSignatures = ['update signature']; + const updateCalldatas = [Bytes.fromI32(312)]; + const updateDescription = '# Updated Title\nUpdated body'; + const updateMessage = 'some update message'; - const parsedProposal = ParsedProposalV3.fromV3Event(newPropEvent); + handleProposalUpdated( + createProposalUpdatedEvent( + txHash, + logIndex, + updateBlockTimestamp, + updateBlockNumber, + proposalId, + proposerWithDelegate, + updateTargets, + updateValues, + updateSignatures, + updateCalldatas, + updateDescription, + updateMessage, + ), + ); - assert.stringEquals(parsedProposal.title, 'Title text'); - assert.stringEquals(parsedProposal.description, propEventInput.description); - }); + const proposal = Proposal.load(proposalId.toString())!; + assert.bigIntEquals(updateBlockTimestamp, proposal.lastUpdatedTimestamp!); + assert.bigIntEquals(updateBlockNumber, proposal.lastUpdatedBlock!); + assert.bytesEquals(changetype(updateTargets)[0], proposal.targets![0]); + assert.bigIntEquals(updateValues[0], proposal.values![0]); + assert.stringEquals(updateSignatures[0], proposal.signatures![0]); + assert.bytesEquals(updateCalldatas[0], proposal.calldatas![0]); + assert.stringEquals(updateDescription, proposal.description!); + assert.stringEquals(extractTitle(updateDescription), proposal.title!); + + const updatedVersionId = txHash.toHexString().concat('-').concat(logIndex.toString()); + const updatedVersion = ProposalVersion.load(updatedVersionId)!; + assert.stringEquals(proposalId.toString(), updatedVersion.proposal); + assert.bigIntEquals(updateBlockTimestamp, updatedVersion.createdAt); + assert.bytesEquals(changetype(updateTargets)[0], updatedVersion.targets![0]); + assert.bigIntEquals(updateValues[0], updatedVersion.values![0]); + assert.stringEquals(updateSignatures[0], updatedVersion.signatures![0]); + assert.bytesEquals(updateCalldatas[0], updatedVersion.calldatas![0]); + assert.stringEquals(updateDescription, updatedVersion.description); + assert.stringEquals(extractTitle(updateDescription), updatedVersion.title); + assert.stringEquals(updateMessage, updatedVersion.updateMessage); }); +}); +describe('ParsedProposalV3', () => { describe('parses signers', () => { test('fromV1Event', () => { const propEventInput = stubProposalCreatedWithRequirementsEventInput(); @@ -771,21 +679,30 @@ describe('forking', () => { describe('Proposal status changes', () => { beforeEach(() => { - const proposalEvent = new ParsedProposalV3(); - proposalEvent.id = proposalId.toString(); - proposalEvent.proposer = proposerWithDelegate.toHexString(); - proposalEvent.targets = changetype([Address.fromString(SOME_ADDRESS)]); - proposalEvent.values = [BigInt.fromI32(123)]; - proposalEvent.signatures = ['some signature']; - proposalEvent.signers = [proposerWithDelegate.toHexString()]; - proposalEvent.calldatas = [Bytes.fromI32(312)]; - proposalEvent.createdTimestamp = updateBlockTimestamp.minus(BIGINT_ONE); - proposalEvent.createdBlock = updateBlockNumber.minus(BIGINT_ONE); - proposalEvent.createdTransactionHash = Bytes.fromI32(11); - proposalEvent.description = 'some description'; - proposalEvent.title = 'some title'; - - handleProposalCreated(proposalEvent); + const propData = new ProposalCreatedData(); + propData.id = proposalId; + propData.proposer = proposerWithDelegate; + propData.targets = [Address.fromString(SOME_ADDRESS)]; + propData.values = [BigInt.fromI32(123)]; + propData.signatures = ['some signature']; + propData.calldatas = [Bytes.fromI32(312)]; + propData.startBlock = BigInt.fromI32(203); + propData.endBlock = BigInt.fromI32(303); + propData.description = 'some description'; + propData.eventBlockNumber = BigInt.fromI32(103); + propData.eventBlockTimestamp = BigInt.fromI32(42); + propData.txHash = Bytes.fromI32(11); + propData.logIndex = BigInt.fromI32(1); + propData.address = Address.fromString(SOME_ADDRESS); + + handleProposalCreated(createProposalCreatedEvent(propData)); + + const propExtraDetails = new ParsedProposalV3(); + propExtraDetails.id = propData.id.toString(); + propExtraDetails.updatePeriodEndBlock = BigInt.fromI32(150); + propExtraDetails.proposalThreshold = BIGINT_ONE; + propExtraDetails.quorumVotes = BIGINT_ONE; + saveProposalExtraDetails(propExtraDetails); }); test('handleProposalCanceled', () => { @@ -800,7 +717,7 @@ describe('Proposal status changes', () => { ); const proposal = Proposal.load(proposalId.toString())!; - assert.stringEquals(STATUS_CANCELLED, proposal.status); + assert.stringEquals(STATUS_CANCELLED, proposal.status!); assert.bigIntEquals(updateBlockTimestamp, proposal.canceledTimestamp!); assert.bigIntEquals(updateBlockNumber, proposal.canceledBlock!); }); @@ -817,7 +734,7 @@ describe('Proposal status changes', () => { ); const proposal = Proposal.load(proposalId.toString())!; - assert.stringEquals(STATUS_VETOED, proposal.status); + assert.stringEquals(STATUS_VETOED, proposal.status!); assert.bigIntEquals(updateBlockTimestamp, proposal.vetoedTimestamp!); assert.bigIntEquals(updateBlockNumber, proposal.vetoedBlock!); }); @@ -836,7 +753,7 @@ describe('Proposal status changes', () => { ); const proposal = Proposal.load(proposalId.toString())!; - assert.stringEquals(STATUS_QUEUED, proposal.status); + assert.stringEquals(STATUS_QUEUED, proposal.status!); assert.bigIntEquals(updateBlockTimestamp, proposal.queuedTimestamp!); assert.bigIntEquals(updateBlockNumber, proposal.queuedBlock!); assert.bigIntEquals(eta, proposal.executionETA!); @@ -854,7 +771,7 @@ describe('Proposal status changes', () => { ); const proposal = Proposal.load(proposalId.toString())!; - assert.stringEquals(STATUS_EXECUTED, proposal.status); + assert.stringEquals(STATUS_EXECUTED, proposal.status!); assert.bigIntEquals(updateBlockTimestamp, proposal.executedTimestamp!); assert.bigIntEquals(updateBlockNumber, proposal.executedBlock!); }); diff --git a/packages/nouns-subgraph/tests/utils.ts b/packages/nouns-subgraph/tests/utils.ts index a230e6f2a5..f1956a5bc4 100644 --- a/packages/nouns-subgraph/tests/utils.ts +++ b/packages/nouns-subgraph/tests/utils.ts @@ -16,6 +16,7 @@ import { ProposalVetoed, ProposalExecuted, ProposalQueued, + ProposalCreated, } from '../src/types/NounsDAO/NounsDAO'; import { handleMinQuorumVotesBPSSet, @@ -23,7 +24,7 @@ import { handleQuorumCoefficientSet, } from '../src/nouns-dao'; import { Address, ethereum, Bytes, BigInt, ByteArray } from '@graphprotocol/graph-ts'; -import { BIGINT_ONE, BIGINT_ZERO } from '../src/utils/constants'; +import { BIGINT_ONE, BIGINT_ZERO, ZERO_ADDRESS } from '../src/utils/constants'; import { ProposalCandidateCreated, SignatureAdded } from '../src/types/NounsDAOData/NounsDAOData'; import { DelegateChanged, @@ -752,3 +753,63 @@ export function createDelegateVotesChangedEvent( return newEvent; } + +export class ProposalCreatedData { + id: BigInt = BIGINT_ZERO; + proposer: Address = Address.fromString(ZERO_ADDRESS); + signers: Address[] = []; + targets: Address[] = []; + values: BigInt[] = []; + signatures: string[] = []; + calldatas: Bytes[] = []; + startBlock: BigInt = BIGINT_ZERO; + endBlock: BigInt = BIGINT_ZERO; + description: string = ''; + eventBlockNumber: BigInt = BIGINT_ZERO; + eventBlockTimestamp: BigInt = BIGINT_ZERO; + txHash: Bytes = Bytes.fromI32(0); + logIndex: BigInt = BIGINT_ZERO; + address: Address = Address.fromString(ZERO_ADDRESS); +} + +export function createProposalCreatedEvent(input: ProposalCreatedData): ProposalCreated { + let newEvent = changetype(newMockEvent()); + newEvent.parameters = new Array(); + + newEvent.parameters.push( + new ethereum.EventParam('id', ethereum.Value.fromUnsignedBigInt(input.id)), + ); + newEvent.parameters.push( + new ethereum.EventParam('proposer', ethereum.Value.fromAddress(input.proposer)), + ); + newEvent.parameters.push( + new ethereum.EventParam('targets', ethereum.Value.fromAddressArray(input.targets)), + ); + newEvent.parameters.push( + new ethereum.EventParam('values', ethereum.Value.fromUnsignedBigIntArray(input.values)), + ); + newEvent.parameters.push( + new ethereum.EventParam('signatures', ethereum.Value.fromStringArray(input.signatures)), + ); + + newEvent.parameters.push( + new ethereum.EventParam('calldatas', ethereum.Value.fromBytesArray(input.calldatas)), + ); + newEvent.parameters.push( + new ethereum.EventParam('startBlock', ethereum.Value.fromUnsignedBigInt(input.startBlock)), + ); + newEvent.parameters.push( + new ethereum.EventParam('endBlock', ethereum.Value.fromUnsignedBigInt(input.endBlock)), + ); + newEvent.parameters.push( + new ethereum.EventParam('description', ethereum.Value.fromString(input.description)), + ); + + newEvent.block.number = input.eventBlockNumber; + newEvent.block.timestamp = input.eventBlockTimestamp; + newEvent.transaction.hash = input.txHash; + newEvent.logIndex = input.logIndex; + newEvent.address = input.address; + + return newEvent; +} diff --git a/packages/nouns-webapp/src/wrappers/nounsDao.ts b/packages/nouns-webapp/src/wrappers/nounsDao.ts index 33ab4524f9..a0dac17341 100644 --- a/packages/nouns-webapp/src/wrappers/nounsDao.ts +++ b/packages/nouns-webapp/src/wrappers/nounsDao.ts @@ -1,8 +1,4 @@ -import { - NounsDAOV2ABI, - NounsDAOV3ABI, - NounsDaoLogicV3Factory, -} from '@nouns/sdk'; +import { NounsDAOV3ABI, NounsDaoLogicFactory } from '@nouns/sdk'; import { ChainId, useBlockNumber, @@ -166,7 +162,7 @@ export interface PartialProposalSubgraphEntity { export interface ProposalSubgraphEntity extends ProposalTransactionDetails, - PartialProposalSubgraphEntity { + PartialProposalSubgraphEntity { description: string; createdBlock: string; createdTransactionHash: string; @@ -266,8 +262,7 @@ export interface ForkSubgraphEntity { } const abi = new utils.Interface(NounsDAOV3ABI); -const abiV2 = new utils.Interface(NounsDAOV2ABI); -const nounsDaoContract = NounsDaoLogicV3Factory.connect(config.addresses.nounsDAOProxy, undefined!); +const nounsDaoContract = NounsDaoLogicFactory.connect(config.addresses.nounsDAOProxy, undefined!); // Start the log search at the mainnet deployment block to speed up log queries const fromBlock = CHAIN_ID === ChainId.Mainnet ? 12985453 : 0; @@ -545,7 +540,11 @@ const getProposalState = ( if (!blockNumber) { return ProposalState.UNDETERMINED; } - if (isDaoGteV3 && proposal.updatePeriodEndBlock && blockNumber <= parseInt(proposal.updatePeriodEndBlock)) { + if ( + isDaoGteV3 && + proposal.updatePeriodEndBlock && + blockNumber <= parseInt(proposal.updatePeriodEndBlock) + ) { return ProposalState.UPDATABLE; } @@ -584,7 +583,7 @@ const getProposalState = ( return ProposalState.UNDETERMINED; } // if v3+ and not on timelock v1, grace period is 21 days, otherwise 14 days - const GRACE_PERIOD = (isDaoGteV3 && !onTimelockV1) ? 21 * 60 * 60 * 24 : 14 * 60 * 60 * 24; + const GRACE_PERIOD = isDaoGteV3 && !onTimelockV1 ? 21 * 60 * 60 * 24 : 14 * 60 * 60 * 24; if (blockTimestamp.getTime() / 1_000 >= parseInt(proposal.executionETA) + GRACE_PERIOD) { return ProposalState.EXPIRED; } @@ -603,11 +602,17 @@ const parsePartialSubgraphProposal = ( if (!proposal) { return; } - const onTimelockV1 = proposal.onTimelockV1 === null ? false : true + const onTimelockV1 = proposal.onTimelockV1 === null ? false : true; return { id: proposal.id, title: proposal.title ?? 'Untitled', - status: getProposalState(blockNumber, new Date((timestamp ?? 0) * 1000), proposal, isDaoGteV3, onTimelockV1), + status: getProposalState( + blockNumber, + new Date((timestamp ?? 0) * 1000), + proposal, + isDaoGteV3, + onTimelockV1, + ), startBlock: parseInt(proposal.startBlock), endBlock: parseInt(proposal.endBlock), updatePeriodEndBlock: parseInt(proposal.updatePeriodEndBlock), @@ -648,13 +653,19 @@ const parseSubgraphProposal = ( } else { details = formatProposalTransactionDetails(transactionDetails); } - const onTimelockV1 = proposal.onTimelockV1 === null ? false : true + const onTimelockV1 = proposal.onTimelockV1 === null ? false : true; return { id: proposal.id, title: R.pipe(extractTitle, removeMarkdownStyle)(description) ?? 'Untitled', description: description ?? 'No description.', proposer: proposal.proposer?.id, - status: getProposalState(blockNumber, new Date((timestamp ?? 0) * 1000), proposal, isDaoGteV3, onTimelockV1), + status: getProposalState( + blockNumber, + new Date((timestamp ?? 0) * 1000), + proposal, + isDaoGteV3, + onTimelockV1, + ), proposalThreshold: parseInt(proposal.proposalThreshold), quorumVotes: parseInt(proposal.quorumVotes), forCount: parseInt(proposal.forVotes), @@ -757,7 +768,7 @@ export const useProposal = (id: string | number, toUpdate?: boolean): Proposal | blockNumber, timestamp, toUpdate, - isDaoGteV3 + isDaoGteV3, ); }; @@ -1062,10 +1073,7 @@ const eventsWithforkCycleEvents = ( id: 'fork-ended', createdAt: endTimestamp ? endTimestamp.toString() : null, }; - const forkEvents: ForkCycleEvent[] = [ - executed, - forkEnded, - ]; + const forkEvents: ForkCycleEvent[] = [executed, forkEnded]; const sortedEvents = [...events, ...forkEvents].sort( ( @@ -1198,12 +1206,16 @@ export const useForks = (pollInterval?: number) => { }; export const useIsForkActive = () => { - const timestamp = parseInt((new Date().getTime() / 1000).toFixed(0)) + const timestamp = parseInt((new Date().getTime() / 1000).toFixed(0)); const { loading, data: forksData, error, - } = useQuery(isForkActiveQuery(timestamp)) as { loading: boolean; data: { forks: Fork[] }; error: Error; }; + } = useQuery(isForkActiveQuery(timestamp)) as { + loading: boolean; + data: { forks: Fork[] }; + error: Error; + }; const data = forksData?.forks.length > 0 ? true : false; return { loading, @@ -1287,22 +1299,6 @@ export const checkHasActiveOrPendingProposalOrCandidate = ( }; export const useIsDaoGteV3 = (): boolean => { - const [implementation] = - useContractCall({ - abi: abiV2, - address: config.addresses.nounsDAOProxy, - method: 'implementation', - }) || []; - if ( - implementation && - config.addresses.nounsDAOLogicV2 && - implementation.toLowerCase() !== config.addresses.nounsDAOLogicV2.toLowerCase() - ) { - return true; - } - if (!config.featureToggles.daoGteV3) { - return false; - } return true; }; @@ -1316,7 +1312,6 @@ export const useLastMinuteWindowInBlocks = (): number | undefined => { return lastMinuteWindowInBlocks?.toNumber(); }; - export const useUpdatableProposalIds = (blockNumber: number) => { const { loading, @@ -1335,4 +1330,4 @@ export const useUpdatableProposalIds = (blockNumber: number) => { data, error, }; -} \ No newline at end of file +}; diff --git a/packages/nouns-webapp/src/wrappers/nounsData.ts b/packages/nouns-webapp/src/wrappers/nounsData.ts index 5f986204f1..c46bea202c 100644 --- a/packages/nouns-webapp/src/wrappers/nounsData.ts +++ b/packages/nouns-webapp/src/wrappers/nounsData.ts @@ -1,5 +1,5 @@ import { utils } from 'ethers'; -import { NounsDAODataABI, NounsDaoDataFactory, NounsDaoLogicV3Factory } from '@nouns/contracts'; +import { NounsDAODataABI, NounsDaoDataFactory, NounsDaoLogicFactory } from '@nouns/contracts'; import { useContractCall, useContractFunction } from '@usedapp/core'; import config from '../config'; import { @@ -38,7 +38,7 @@ export interface VoteSignalDetail { }; } -const nounsDaoContract = NounsDaoLogicV3Factory.connect(config.addresses.nounsDAOProxy, undefined!); +const nounsDaoContract = NounsDaoLogicFactory.connect(config.addresses.nounsDAOProxy, undefined!); export const useCreateProposalCandidate = () => { const { send: createProposalCandidate, state: createProposalCandidateState } = @@ -62,7 +62,6 @@ export const useAddSignature = () => { return { addSignature, addSignatureState }; }; - const deDupeSigners = (signers: string[]) => { const uniqueSigners: string[] = []; signers.forEach(signer => { @@ -79,7 +78,7 @@ const filterSigners = ( activePendingProposers: string[], signers?: CandidateSignature[], proposalIdToUpdate?: number, - updatableProposalIds?: number[] + updatableProposalIds?: number[], ) => { const sigsFiltered = signers?.filter( sig => sig.canceled === false && sig.expirationTimestamp > timestampNow, @@ -93,8 +92,10 @@ const filterSigners = ( ?.nounsRepresented.length || 0; // don't count votes from signers who have active or pending proposals // but include them in the list of signers to display with a note that they have an active proposal - const parentProposalIsUpdatable = proposalIdToUpdate && updatableProposalIds?.includes(proposalIdToUpdate ?? 0); - const activeOrPendingProposal = !parentProposalIsUpdatable && activePendingProposers.includes(signature.signer.id); + const parentProposalIsUpdatable = + proposalIdToUpdate && updatableProposalIds?.includes(proposalIdToUpdate ?? 0); + const activeOrPendingProposal = + !parentProposalIsUpdatable && activePendingProposers.includes(signature.signer.id); if (!activeOrPendingProposal) { voteCount += delegateVoteCount; } @@ -103,17 +104,15 @@ const filterSigners = ( signer: { ...signature.signer, voteCount: delegateVoteCount, - activeOrPendingProposal: activeOrPendingProposal + activeOrPendingProposal: activeOrPendingProposal, }, }; activeSigs.push(sigWithVotes); }); - const filteredSignatures = activeSigs.filter( - (signature: CandidateSignature) => { - return signature.canceled === false && signature.expirationTimestamp > timestampNow / 1000; - }, - ); + const filteredSignatures = activeSigs.filter((signature: CandidateSignature) => { + return signature.canceled === false && signature.expirationTimestamp > timestampNow / 1000; + }); const sortedSignatures = [...filteredSignatures].sort((a, b) => { return a.expirationTimestamp - b.expirationTimestamp; }); @@ -124,29 +123,39 @@ const filterSigners = ( export const useCandidateProposals = (blockNumber?: number) => { const timestampNow = Math.floor(Date.now() / 1000); // in seconds const { loading, data: candidates, error } = useQuery(candidateProposalsQuery()); - const unmatchedCandidates: ProposalCandidateSubgraphEntity[] = candidates?.proposalCandidates?.filter( - (candidate: ProposalCandidateSubgraphEntity) => - candidate.latestVersion.content.matchingProposalIds.length === 0 && - candidate.canceled === false, - ); + const unmatchedCandidates: ProposalCandidateSubgraphEntity[] = + candidates?.proposalCandidates?.filter( + (candidate: ProposalCandidateSubgraphEntity) => + candidate.latestVersion.content.matchingProposalIds.length === 0 && + candidate.canceled === false, + ); const activeCandidateProposers = unmatchedCandidates?.map( (candidate: ProposalCandidateSubgraphEntity) => candidate.proposer, ); - const proposerDelegates = - useDelegateNounsAtBlockQuery(activeCandidateProposers, blockNumber ?? 0); + const proposerDelegates = useDelegateNounsAtBlockQuery( + activeCandidateProposers, + blockNumber ?? 0, + ); const threshold = useProposalThreshold() || 0; const activePendingProposers = useActivePendingUpdatableProposers(blockNumber ?? 0); - const allSigners = unmatchedCandidates?.map( - (candidate: ProposalCandidateSubgraphEntity) => + const allSigners = unmatchedCandidates + ?.map((candidate: ProposalCandidateSubgraphEntity) => candidate.latestVersion.content.contentSignatures?.map( (sig: CandidateSignature) => sig.signer.id, ), - ).flat(); - const signersDelegateSnapshot = useDelegateNounsAtBlockQuery(allSigners ? deDupeSigners(allSigners) : [], blockNumber ?? 0); + ) + .flat(); + const signersDelegateSnapshot = useDelegateNounsAtBlockQuery( + allSigners ? deDupeSigners(allSigners) : [], + blockNumber ?? 0, + ); const updatableProposalIds = useUpdatableProposalIds(blockNumber ?? 0); - const candidatesData = proposerDelegates.data && unmatchedCandidates?.map( - (candidate: ProposalCandidateSubgraphEntity) => { - const proposerVotes = proposerDelegates.data?.delegates.find(d => d.id === candidate.proposer.toLowerCase())?.nounsRepresented?.length || 0; + const candidatesData = + proposerDelegates.data && + unmatchedCandidates?.map((candidate: ProposalCandidateSubgraphEntity) => { + const proposerVotes = + proposerDelegates.data?.delegates.find(d => d.id === candidate.proposer.toLowerCase()) + ?.nounsRepresented?.length || 0; const parsedData = parseSubgraphCandidate( candidate, proposerVotes, @@ -155,19 +164,24 @@ export const useCandidateProposals = (blockNumber?: number) => { activePendingProposers.data, false, signersDelegateSnapshot.data, - updatableProposalIds.data + updatableProposalIds.data, ); return parsedData; - }, - ); + }); - candidatesData && candidatesData?.sort((a, b) => { - return a.lastUpdatedTimestamp - b.lastUpdatedTimestamp; - }); + candidatesData && + candidatesData?.sort((a, b) => { + return a.lastUpdatedTimestamp - b.lastUpdatedTimestamp; + }); return { loading, data: candidatesData, error }; }; -export const useCandidateProposal = (id: string, pollInterval?: number, toUpdate?: boolean, blockNumber?: number) => { +export const useCandidateProposal = ( + id: string, + pollInterval?: number, + toUpdate?: boolean, + blockNumber?: number, +) => { const timestampNow = Math.floor(Date.now() / 1000); // in seconds const { loading, data, error, refetch } = useQuery(candidateProposalQuery(id), { pollInterval: pollInterval || 0, @@ -176,22 +190,30 @@ export const useCandidateProposal = (id: string, pollInterval?: number, toUpdate const threshold = useProposalThreshold() || 0; const versionSignatures = data?.proposalCandidate.latestVersion.content.contentSignatures; const allSigners = versionSignatures?.map((sig: CandidateSignature) => sig.signer.id); - const proposerDelegates = - useDelegateNounsAtBlockQuery([data?.proposalCandidate.proposer], blockNumber || 0); + const proposerDelegates = useDelegateNounsAtBlockQuery( + [data?.proposalCandidate.proposer], + blockNumber || 0, + ); const proposerNounVotes = (proposerDelegates.data && proposerDelegates.data.delegates[0]?.nounsRepresented?.length) || 0; - const signersDelegateSnapshot = useDelegateNounsAtBlockQuery(allSigners ? deDupeSigners(allSigners) : [], blockNumber ?? 0); - const updatableProposalIds = useUpdatableProposalIds(blockNumber ?? 0); - const parsedData = proposerDelegates.data && data?.proposalCandidate && parseSubgraphCandidate( - data.proposalCandidate, - proposerNounVotes, - threshold, - timestampNow, - activePendingProposers.data, - toUpdate, - signersDelegateSnapshot.data, - updatableProposalIds.data + const signersDelegateSnapshot = useDelegateNounsAtBlockQuery( + allSigners ? deDupeSigners(allSigners) : [], + blockNumber ?? 0, ); + const updatableProposalIds = useUpdatableProposalIds(blockNumber ?? 0); + const parsedData = + proposerDelegates.data && + data?.proposalCandidate && + parseSubgraphCandidate( + data.proposalCandidate, + proposerNounVotes, + threshold, + timestampNow, + activePendingProposers.data, + toUpdate, + signersDelegateSnapshot.data, + updatableProposalIds.data, + ); return { loading, data: parsedData, error, refetch }; }; @@ -300,7 +322,7 @@ const parseSubgraphCandidate = ( activePendingProposers: string[], toUpdate?: boolean, delegateSnapshot?: Delegates, - updatableProposalIds?: number[] + updatableProposalIds?: number[], ) => { const description = candidate.latestVersion.content.description ?.replace(/\\n/g, '\n') @@ -324,8 +346,10 @@ const parseSubgraphCandidate = ( delegateSnapshot, activePendingProposers, candidate.latestVersion.content.contentSignatures, - candidate.latestVersion.content.proposalIdToUpdate ? parseInt(candidate.latestVersion.content.proposalIdToUpdate) : undefined, - updatableProposalIds + candidate.latestVersion.content.proposalIdToUpdate + ? parseInt(candidate.latestVersion.content.proposalIdToUpdate) + : undefined, + updatableProposalIds, ); const requiredVotes = threshold + 1 - proposerVotes > 0 ? threshold + 1 - proposerVotes : 0; return { diff --git a/yarn.lock b/yarn.lock index 443247cf5e..465b66ff9d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5082,6 +5082,11 @@ dependencies: antlr4ts "^0.5.0-alpha.4" +"@solidity-parser/parser@^0.17.0": + version "0.17.0" + resolved "https://registry.yarnpkg.com/@solidity-parser/parser/-/parser-0.17.0.tgz#52a2fcc97ff609f72011014e4c5b485ec52243ef" + integrity sha512-Nko8R0/kUo391jsEHHxrGM07QFdnPGvlmox4rmH0kNiNAashItAilhy4Mv4pK5gQmW5f4sXAF58fwJbmlkGcVw== + "@stablelib/aead@^1.0.1": version "1.0.1" resolved "https://registry.npmjs.org/@stablelib/aead/-/aead-1.0.1.tgz#c4b1106df9c23d1b867eb9b276d8f42d5fc4c0c3" @@ -11455,11 +11460,6 @@ emittery@^0.7.1: resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.7.2.tgz#25595908e13af0f5674ab419396e2fb394cdfa82" integrity sha512-A8OG5SR/ij3SsJdWDJdkkSYUjQdCUx6APQXem0SaEePBSRg4eymGYwBkKo1Y6DU+af/Jn2dBQqDBvjnr9Vi8nQ== -emoji-regex@^10.0.0: - version "10.0.0" - resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-10.0.0.tgz#96559e19f82231b436403e059571241d627c42b8" - integrity sha512-KmJa8l6uHi1HrBI34udwlzZY1jOEuID/ft4d8BSSEdRyap7PwBEt910453PJa5MuGvxkLqlt4Uvhu7tttFHViw== - emoji-regex@^7.0.1: version "7.0.3" resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" @@ -20643,17 +20643,14 @@ prepend-http@^2.0.0: resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-2.0.0.tgz#e92434bfa5ea8c19f41cdfd401d741a3c819d897" integrity sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc= -prettier-plugin-solidity@^1.0.0-beta.12: - version "1.0.0-beta.19" - resolved "https://registry.yarnpkg.com/prettier-plugin-solidity/-/prettier-plugin-solidity-1.0.0-beta.19.tgz#7c3607fc4028f5e6a425259ff03e45eedf733df3" - integrity sha512-xxRQ5ZiiZyUoMFLE9h7HnUDXI/daf1tnmL1msEdcKmyh7ZGQ4YklkYLC71bfBpYU2WruTb5/SFLUaEb3RApg5g== +prettier-plugin-solidity@^1.2.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/prettier-plugin-solidity/-/prettier-plugin-solidity-1.3.1.tgz#59944d3155b249f7f234dee29f433524b9a4abcf" + integrity sha512-MN4OP5I2gHAzHZG1wcuJl0FsLS3c4Cc5494bbg+6oQWBPuEamjwDvmGfFMZ6NFzsh3Efd9UUxeT7ImgjNH4ozA== dependencies: - "@solidity-parser/parser" "^0.14.0" - emoji-regex "^10.0.0" - escape-string-regexp "^4.0.0" - semver "^7.3.5" - solidity-comments-extractor "^0.0.7" - string-width "^4.2.3" + "@solidity-parser/parser" "^0.17.0" + semver "^7.5.4" + solidity-comments-extractor "^0.0.8" prettier@1.19.1: version "1.19.1" @@ -22629,7 +22626,7 @@ semver@^6.0.0, semver@^6.1.1, semver@^6.1.2, semver@^6.2.0, semver@^6.3.0: resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== -semver@^7.3.7: +semver@^7.3.7, semver@^7.5.4: version "7.5.4" resolved "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e" integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA== @@ -23059,10 +23056,10 @@ solidity-ast@^0.4.15: resolved "https://registry.yarnpkg.com/solidity-ast/-/solidity-ast-0.4.28.tgz#5589998512b9a3602e6ba612cbe7fed7401294f4" integrity sha512-RtZCP5tSvZMadVtg9/IfLmAMKDOnQEvG2HA6VnPuoTMxqxsbbn4lQy8jgH3RVbqW0eO1hd7cSCKecb72/OeOIw== -solidity-comments-extractor@^0.0.7: - version "0.0.7" - resolved "https://registry.yarnpkg.com/solidity-comments-extractor/-/solidity-comments-extractor-0.0.7.tgz#99d8f1361438f84019795d928b931f4e5c39ca19" - integrity sha512-wciNMLg/Irp8OKGrh3S2tfvZiZ0NEyILfcRCXCD4mp7SgK/i9gzLfhY2hY7VMCQJ3kH9UB9BzNdibIVMchzyYw== +solidity-comments-extractor@^0.0.8: + version "0.0.8" + resolved "https://registry.yarnpkg.com/solidity-comments-extractor/-/solidity-comments-extractor-0.0.8.tgz#f6e148ab0c49f30c1abcbecb8b8df01ed8e879f8" + integrity sha512-htM7Vn6LhHreR+EglVMd2s+sZhcXAirB1Zlyrv5zBuTxieCvjfnRpd7iZk75m/u6NOlEyQ94C6TWbBn2cY7w8g== solidity-coverage@0.7.21: version "0.7.21"