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 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"