diff --git a/packages/nouns-contracts/contracts/test/ERC20Testnet.sol b/packages/nouns-contracts/contracts/test/ERC20Testnet.sol new file mode 100644 index 0000000000..a2e92f68ce --- /dev/null +++ b/packages/nouns-contracts/contracts/test/ERC20Testnet.sol @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: GPL-3.0 + +pragma solidity ^0.8.19; + +import { Ownable } from '@openzeppelin/contracts/access/Ownable.sol'; +import { ERC20 } from '@openzeppelin/contracts/token/ERC20/ERC20.sol'; + +contract ERC20Testnet is ERC20, Ownable { + constructor( + address owner_, + string memory name_, + string memory symbol_ + ) ERC20(name_, symbol_) { + _transferOwnership(owner_); + } + + function mint(address to, uint256 amount) external onlyOwner { + _mint(to, amount); + } +} diff --git a/packages/nouns-contracts/contracts/test/RocketETHTestnet.sol b/packages/nouns-contracts/contracts/test/RocketETHTestnet.sol new file mode 100644 index 0000000000..246728e2f9 --- /dev/null +++ b/packages/nouns-contracts/contracts/test/RocketETHTestnet.sol @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: GPL-3.0 + +pragma solidity ^0.8.19; + +import { Ownable } from '@openzeppelin/contracts/access/Ownable.sol'; +import { ERC20 } from '@openzeppelin/contracts/token/ERC20/ERC20.sol'; + +contract RocketETHTestnet is ERC20, Ownable { + uint256 rate; + + constructor(address owner_) ERC20('Rocket ETH Testnet', 'rETH') { + _transferOwnership(owner_); + } + + function mint(address to, uint256 amount) external onlyOwner { + _mint(to, amount); + } + + function setRate(uint256 rate_) public onlyOwner { + rate = rate_; + } + + function getEthValue(uint256 _rethAmount) external view returns (uint256) { + return _rethAmount * rate; + } +} diff --git a/packages/nouns-contracts/script/DeployAuctionHouseV2.s.sol b/packages/nouns-contracts/script/DeployAuctionHouseV2Base.s.sol similarity index 94% rename from packages/nouns-contracts/script/DeployAuctionHouseV2.s.sol rename to packages/nouns-contracts/script/DeployAuctionHouseV2Base.s.sol index b5b6ee7d3e..9567ffd6f6 100644 --- a/packages/nouns-contracts/script/DeployAuctionHouseV2.s.sol +++ b/packages/nouns-contracts/script/DeployAuctionHouseV2Base.s.sol @@ -6,7 +6,7 @@ import { NounsAuctionHouse } from '../contracts/NounsAuctionHouse.sol'; import { NounsAuctionHouseV2 } from '../contracts/NounsAuctionHouseV2.sol'; import { NounsAuctionHousePreV2Migration } from '../contracts/NounsAuctionHousePreV2Migration.sol'; -contract DeployAuctionHouseV2 is Script { +abstract contract DeployAuctionHouseV2Base is Script { NounsAuctionHouse public immutable auctionV1; constructor(address _auctionHouseProxy) { diff --git a/packages/nouns-contracts/script/DeployAuctionHouseV2Sepolia.s.sol b/packages/nouns-contracts/script/DeployAuctionHouseV2Sepolia.s.sol new file mode 100644 index 0000000000..c86e68d053 --- /dev/null +++ b/packages/nouns-contracts/script/DeployAuctionHouseV2Sepolia.s.sol @@ -0,0 +1,15 @@ +// 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 { DeployAuctionHouseV2Base } from './DeployAuctionHouseV2Base.s.sol'; + +contract DeployAuctionHouseV2Sepolia is DeployAuctionHouseV2Base { + address constant AUCTION_HOUSE_SEPOLIA = 0x45ebbdb0E66aC2a8339D98aDB6934C89f166A754; + + constructor() DeployAuctionHouseV2Base(AUCTION_HOUSE_SEPOLIA) {} +} diff --git a/packages/nouns-contracts/script/executorV3AndExcessETHBurner/DeployExecutorV3AndExcessETHBurnerBase.s.sol b/packages/nouns-contracts/script/executorV3AndExcessETHBurner/DeployExecutorV3AndExcessETHBurnerBase.s.sol new file mode 100644 index 0000000000..9ab42b923e --- /dev/null +++ b/packages/nouns-contracts/script/executorV3AndExcessETHBurner/DeployExecutorV3AndExcessETHBurnerBase.s.sol @@ -0,0 +1,65 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity ^0.8.19; + +import 'forge-std/Script.sol'; +import { NounsDAOExecutorV3 } from '../../contracts/governance/NounsDAOExecutorV3.sol'; +import { ExcessETHBurner, INounsDAOV3 } from '../../contracts/governance/ExcessETHBurner.sol'; +import { NounsDAOLogicV3 } from '../../contracts/governance/NounsDAOLogicV3.sol'; +import { INounsAuctionHouseV2 } from '../../contracts/interfaces/INounsAuctionHouseV2.sol'; +import { IERC20 } from '@openzeppelin/contracts/interfaces/IERC20.sol'; + +abstract contract DeployExecutorV3AndExcessETHBurnerBase is Script { + address public immutable executorProxy; + NounsDAOLogicV3 public immutable daoProxy; + INounsAuctionHouseV2 public immutable auction; + IERC20 wETH; + IERC20 stETH; + IERC20 rETH; + uint128 burnStartNounID; + uint128 minNewNounsBetweenBurns; + uint16 numberOfPastAuctionsForMeanPrice; + + constructor( + address payable executorProxy_, + address wETH_, + address stETH_, + address rETH_, + uint128 burnStartNounID_, + uint128 minNewNounsBetweenBurns_, + uint16 numberOfPastAuctionsForMeanPrice_ + ) { + executorProxy = executorProxy_; + + daoProxy = NounsDAOLogicV3(payable(NounsDAOExecutorV3(executorProxy_).admin())); + auction = INounsAuctionHouseV2(daoProxy.nouns().minter()); + + wETH = IERC20(wETH_); + stETH = IERC20(stETH_); + rETH = IERC20(rETH_); + + burnStartNounID = burnStartNounID_; + minNewNounsBetweenBurns = minNewNounsBetweenBurns_; + numberOfPastAuctionsForMeanPrice = numberOfPastAuctionsForMeanPrice_; + } + + function run() public returns (NounsDAOExecutorV3 executorV3, ExcessETHBurner burner) { + uint256 deployerKey = vm.envUint('DEPLOYER_PRIVATE_KEY'); + + vm.startBroadcast(deployerKey); + + executorV3 = new NounsDAOExecutorV3(); + burner = new ExcessETHBurner( + executorProxy, + INounsDAOV3(address(daoProxy)), + auction, + wETH, + stETH, + rETH, + burnStartNounID, + minNewNounsBetweenBurns, + numberOfPastAuctionsForMeanPrice + ); + + vm.stopBroadcast(); + } +} diff --git a/packages/nouns-contracts/script/executorV3AndExcessETHBurner/DeployExecutorV3AndExcessETHBurnerSepolia.s.sol b/packages/nouns-contracts/script/executorV3AndExcessETHBurner/DeployExecutorV3AndExcessETHBurnerSepolia.s.sol new file mode 100644 index 0000000000..8c2b7db64a --- /dev/null +++ b/packages/nouns-contracts/script/executorV3AndExcessETHBurner/DeployExecutorV3AndExcessETHBurnerSepolia.s.sol @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity ^0.8.19; + +import 'forge-std/Script.sol'; +import { DeployExecutorV3AndExcessETHBurnerBase } from './DeployExecutorV3AndExcessETHBurnerBase.s.sol'; +import { NounsDAOExecutorV3 } from '../../contracts/governance/NounsDAOExecutorV3.sol'; +import { ExcessETHBurner, INounsDAOV3 } from '../../contracts/governance/ExcessETHBurner.sol'; +import { NounsDAOLogicV3 } from '../../contracts/governance/NounsDAOLogicV3.sol'; +import { INounsAuctionHouseV2 } from '../../contracts/interfaces/INounsAuctionHouseV2.sol'; +import { IERC20 } from '@openzeppelin/contracts/interfaces/IERC20.sol'; + +contract DeployExecutorV3AndExcessETHBurnerSepolia is DeployExecutorV3AndExcessETHBurnerBase { + address payable constant EXECUTOR_PROXY = payable(0x6c2dD53b8DbDD3af1209DeB9dA87D487EaE8E638); + address constant WETH = 0xfFf9976782d46CC05630D1f6eBAb18b2324d6B14; + address constant STETH = 0x7f96dAEF4A54F6A52613d6272560C2BD25e913B8; + address constant RETH = 0xf07dafCC49a9F5E1E73Df6bD6616d0a5bA19e502; + + uint128 BURN_START_NOUN_ID = 10; + uint128 MIN_NOUNS_BETWEEN_BURNS = 10; + uint16 MEAN_AUCTION_COUNT = 10; + + constructor() + DeployExecutorV3AndExcessETHBurnerBase( + EXECUTOR_PROXY, + WETH, + STETH, + RETH, + BURN_START_NOUN_ID, + MIN_NOUNS_BETWEEN_BURNS, + MEAN_AUCTION_COUNT + ) + {} +} diff --git a/packages/nouns-contracts/script/executorV3AndExcessETHBurner/DeployTestnetTokens.s.sol b/packages/nouns-contracts/script/executorV3AndExcessETHBurner/DeployTestnetTokens.s.sol new file mode 100644 index 0000000000..4012403dc6 --- /dev/null +++ b/packages/nouns-contracts/script/executorV3AndExcessETHBurner/DeployTestnetTokens.s.sol @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity ^0.8.19; + +import 'forge-std/Script.sol'; +import { RocketETHTestnet } from '../../contracts/test/RocketETHTestnet.sol'; +import { ERC20Testnet } from '../../contracts/test/ERC20Testnet.sol'; + +contract DeployTestnetTokens is Script { + function run() public { + uint256 deployerKey = vm.envUint('DEPLOYER_PRIVATE_KEY'); + address owner = vm.addr(deployerKey); + + vm.startBroadcast(deployerKey); + + ERC20Testnet stETH = new ERC20Testnet(owner, 'Test Staked Ether', 'stETH'); + RocketETHTestnet rETH = new RocketETHTestnet(owner); + + console.log('Owner: %s', owner); + console.log('stETH: %s', address(stETH)); + console.log('rETH: %s', address(rETH)); + + vm.stopBroadcast(); + } +} diff --git a/packages/nouns-contracts/script/executorV3AndExcessETHBurner/ProposeExecutorV3UpgradeBase.s.sol b/packages/nouns-contracts/script/executorV3AndExcessETHBurner/ProposeExecutorV3UpgradeBase.s.sol new file mode 100644 index 0000000000..720f3552c9 --- /dev/null +++ b/packages/nouns-contracts/script/executorV3AndExcessETHBurner/ProposeExecutorV3UpgradeBase.s.sol @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity ^0.8.15; + +import 'forge-std/Script.sol'; +import { NounsDAOLogicV3 } from '../../contracts/governance/NounsDAOLogicV3.sol'; + +abstract contract ProposeExecutorV3UpgradeBase is Script { + uint256 proposerKey; + string description; + NounsDAOLogicV3 daoProxy; + address executorProxy; + address executorV3Impl; + + function run() public returns (uint256 proposalId) { + vm.startBroadcast(proposerKey); + + uint8 numTxs = 1; + address[] memory targets = new address[](numTxs); + uint256[] memory values = new uint256[](numTxs); + string[] memory signatures = new string[](numTxs); + bytes[] memory calldatas = new bytes[](numTxs); + + // Upgrade to executor V3 + uint256 i = 0; + targets[i] = executorProxy; + values[i] = 0; + signatures[i] = 'upgradeTo(address)'; + calldatas[i] = abi.encode(executorV3Impl); + + proposalId = daoProxy.propose(targets, values, signatures, calldatas, description); + console.log('Proposed proposalId: %d', proposalId); + + vm.stopBroadcast(); + } +} diff --git a/packages/nouns-contracts/script/executorV3AndExcessETHBurner/ProposeExecutorV3UpgradeMainnet.s.sol b/packages/nouns-contracts/script/executorV3AndExcessETHBurner/ProposeExecutorV3UpgradeMainnet.s.sol new file mode 100644 index 0000000000..2b76337073 --- /dev/null +++ b/packages/nouns-contracts/script/executorV3AndExcessETHBurner/ProposeExecutorV3UpgradeMainnet.s.sol @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity ^0.8.15; + +import 'forge-std/Script.sol'; +import { ProposeExecutorV3UpgradeBase } from './ProposeExecutorV3UpgradeBase.s.sol'; +import { NounsDAOLogicV3 } from '../../contracts/governance/NounsDAOLogicV3.sol'; + +contract ProposeDAOV3UpgradeMainnet is ProposeExecutorV3UpgradeBase { + NounsDAOLogicV3 public constant NOUNS_DAO_PROXY_MAINNET = + NounsDAOLogicV3(payable(0x6f3E6272A167e8AcCb32072d08E0957F9c79223d)); + address public constant EXECUTOR_PROXY_MAINNET = 0xb1a32FC9F9D8b2cf86C068Cae13108809547ef71; + address public constant EXECUTOR_V3_IMPL = address(0); + + constructor() { + proposerKey = vm.envUint('PROPOSER_KEY'); + description = vm.readFile(vm.envString('PROPOSAL_DESCRIPTION_FILE')); + daoProxy = NOUNS_DAO_PROXY_MAINNET; + executorProxy = EXECUTOR_PROXY_MAINNET; + executorV3Impl = EXECUTOR_V3_IMPL; + } +} diff --git a/packages/nouns-sdk/src/contract/addresses.json b/packages/nouns-sdk/src/contract/addresses.json index 72acf59950..f27b823c28 100644 --- a/packages/nouns-sdk/src/contract/addresses.json +++ b/packages/nouns-sdk/src/contract/addresses.json @@ -54,17 +54,16 @@ "nounsDAOData": "0x09635F643e140090A9A8Dcd712eD6285858ceBef" }, "11155111": { - "nounsToken": "0x4C4674bb72a096855496a7204962297bd7e12b85", - "nounsSeeder": "0xe99b8Ee07B28C587B755f348649f3Ee45aDA5E7D", - "nounsDescriptor": "0x5319dbcb313738aD70a3D945E61ceB8b84691928", - "nftDescriptor": "0xF5A7A2f948b6b2B1BD6E25C6ddE4dA892301caB5", - "nounsAuctionHouse": "0x44FeBD884Abf796d2d198974A768CBD882a959a8", - "nounsAuctionHouseProxy": "0x488609b7113FCf3B761A05956300d605E8f6BcAf", - "nounsAuctionHouseProxyAdmin": "0x9A19E520d9cd6c40eCc79623f16390a68962b7E9", - "nounsDaoExecutor": "0x332db58b51393f3a6b28d4DD8964234967e1aD33", - "nounsDaoExecutorProxy": "0x07e5D6a1550aD5E597A9b0698A474AA080A2fB28", - "nounsDAOProxy": "0x35d2670d7C8931AACdd37C89Ddcb0638c3c44A57", - "nounsDAOLogicV2": "0x1634D5abB2c0BBF7B817b791C8355a39f2EcEF0A", - "nounsDAOData": "0x9040f720AA8A693F950B9cF94764b4b06079D002" + "nounsToken": "0x2824dcE6253476cBfAB91764F5715763d6e451a3", + "nounsSeeder": "0x8CfedAb19379615f76f31F8c8dCaDf7cE883e7A4", + "nounsDescriptor": "0x163EC071da05E49F49c44961CA4Db90Fb15711BE", + "nftDescriptor": "0x503FE998a52dCbe908A7572ed548c222423B753d", + "nounsAuctionHouse": "0x59A4C36d2c4e1942433a21649e7d0e9ad8E5EdFD", + "nounsAuctionHouseProxy": "0x45ebbdb0E66aC2a8339D98aDB6934C89f166A754", + "nounsAuctionHouseProxyAdmin": "0x7aC3910999565801A0F2ad8623933B3fb1c488ab", + "nounsDaoExecutor": "0x6c2dD53b8DbDD3af1209DeB9dA87D487EaE8E638", + "nounsDAOProxy": "0xBE875f62C35124e27C3F638164049617b883B746", + "nounsDAOLogicV1": "0xe67E2e26E89E1F08227F55A2b8CB42f6028c6b61", + "nounsDAOData": "0x6D1aa9B6Ee004deBE34390d8bc7602A36a4b9655" } } diff --git a/packages/nouns-subgraph/config/sepolia.json b/packages/nouns-subgraph/config/sepolia.json index d32289d597..069e7c334d 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": "0x2824dcE6253476cBfAB91764F5715763d6e451a3", + "startBlock": 4418279 }, "nounsAuctionHouse": { - "address": "0x488609b7113FCf3B761A05956300d605E8f6BcAf", - "startBlock": 3594636 + "address": "0x45ebbdb0E66aC2a8339D98aDB6934C89f166A754", + "startBlock": 4418279 }, "nounsDAO": { - "address": "0x35d2670d7C8931AACdd37C89Ddcb0638c3c44A57", - "startBlock": 3594636 + "address": "0xBE875f62C35124e27C3F638164049617b883B746", + "startBlock": 4418279 }, "nounsDAOData": { - "address": "0x9040f720AA8A693F950B9cF94764b4b06079D002", - "startBlock": 3594636 + "address": "0x6D1aa9B6Ee004deBE34390d8bc7602A36a4b9655", + "startBlock": 4418279 } } diff --git a/packages/nouns-subgraph/package.json b/packages/nouns-subgraph/package.json index c457df013d..0b0d1caf05 100644 --- a/packages/nouns-subgraph/package.json +++ b/packages/nouns-subgraph/package.json @@ -26,7 +26,7 @@ "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:sepolia": "yarn clean && yarn prepare:sepolia && yarn codegen && yarn graph build && goldsky subgraph deploy nouns-sepolia-the-burn/0.1.0", "deploy:mainnet": "yarn clean && yarn prepare:mainnet && yarn codegen && yarn graph build && goldsky subgraph deploy nouns/0.2.0", "mustache": "mustache" }, diff --git a/packages/nouns-webapp/src/config.ts b/packages/nouns-webapp/src/config.ts index 30be08b567..a1fa63f636 100644 --- a/packages/nouns-webapp/src/config.ts +++ b/packages/nouns-webapp/src/config.ts @@ -78,7 +78,7 @@ const app: Record = { jsonRpcUri: createNetworkHttpUrl('sepolia'), wsRpcUri: createNetworkWsUrl('sepolia'), subgraphApiUri: - 'https://api.goldsky.com/api/public/project_cldf2o9pqagp43svvbk5u3kmo/subgraphs/nouns-sepolia-elad/0.1.1/gn', + 'https://api.goldsky.com/api/public/project_cldf2o9pqagp43svvbk5u3kmo/subgraphs/nouns-sepolia-the-burn/0.1.0/gn', enableHistory: process.env.REACT_APP_ENABLE_HISTORY === 'true', }, [ChainId.Mainnet]: { @@ -143,7 +143,7 @@ const getAddresses = (): ContractAddresses => { let nounsAddresses = {} as NounsContractAddresses; try { nounsAddresses = getContractAddressesForChainOrThrow(CHAIN_ID); - } catch { } + } catch {} return { ...nounsAddresses, ...externalAddresses[CHAIN_ID] }; };