-
Notifications
You must be signed in to change notification settings - Fork 431
/
ForkDAODeployer.sol
170 lines (143 loc) · 7.25 KB
/
ForkDAODeployer.sol
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
// SPDX-License-Identifier: GPL-3.0
/// @title The deployer of new Nouns DAO forks
/*********************************
* ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ *
* ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ *
* ░░░░░░█████████░░█████████░░░ *
* ░░░░░░██░░░████░░██░░░████░░░ *
* ░░██████░░░████████░░░████░░░ *
* ░░██░░██░░░████░░██░░░████░░░ *
* ░░██░░██░░░████░░██░░░████░░░ *
* ░░░░░░█████████░░█████████░░░ *
* ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ *
* ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ *
*********************************/
pragma solidity ^0.8.19;
import { ERC1967Proxy } from '@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.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 { 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);
/// @notice The token implementation address
address public immutable tokenImpl;
/// @notice The auction house implementation address
address public immutable auctionImpl;
/// @notice The treasury implementation address
address public immutable treasuryImpl;
/// @notice The governor implementation address
address public immutable governorImpl;
/// @notice The maximum duration of the governance delay in new DAOs
uint256 public immutable delayedGovernanceMaxDuration;
/// @notice The initial voting period in new DAOs, in blocks
uint256 public immutable initialVotingPeriod;
/// @notice The initial voting delay in new DAOs, in blocks
uint256 public immutable initialVotingDelay;
/// @notice The initial proposal threshold in new DAOs, in BPS
uint256 public immutable initialProposalThresholdBPS;
/// @notice The initial quorum votes in new DAOs, in BPS
uint256 public immutable initialQuorumVotesBPS;
constructor(
address tokenImpl_,
address auctionImpl_,
address governorImpl_,
address treasuryImpl_,
uint256 delayedGovernanceMaxDuration_,
uint256 initialVotingPeriod_,
uint256 initialVotingDelay_,
uint256 initialProposalThresholdBPS_,
uint256 initialQuorumVotesBPS_
) {
tokenImpl = tokenImpl_;
auctionImpl = auctionImpl_;
governorImpl = governorImpl_;
treasuryImpl = treasuryImpl_;
delayedGovernanceMaxDuration = delayedGovernanceMaxDuration_;
initialVotingPeriod = initialVotingPeriod_;
initialVotingDelay = initialVotingDelay_;
initialProposalThresholdBPS = initialProposalThresholdBPS_;
initialQuorumVotesBPS = initialQuorumVotesBPS_;
}
/**
* @notice Deploys a new Nouns DAO fork, including a new token, auction house, governor, and treasury.
* All contracts are upgradable, and are almost entirely initialized with the same parameters as the original DAO.
* @param forkingPeriodEndTimestamp The timestamp at which the forking period ends
* @param forkEscrow The address of the fork escrow contract, used for claiming tokens that were escrowed in the original DAO
* and to get references to the original DAO's auction house and timelock
* @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) {
token = address(new ERC1967Proxy(tokenImpl, ''));
address auction = address(new ERC1967Proxy(auctionImpl, ''));
address governor = address(new ERC1967Proxy(governorImpl, ''));
treasury = address(new ERC1967Proxy(treasuryImpl, ''));
NounsAuctionHouse originalAuction = getOriginalAuction(forkEscrow);
NounsDAOExecutorV2 originalTimelock = getOriginalTimelock(forkEscrow);
NounsTokenFork(token).initialize(
treasury,
auction,
forkEscrow,
forkEscrow.forkId(),
getStartNounId(originalAuction),
forkEscrow.numTokensInEscrow(),
forkingPeriodEndTimestamp
);
NounsAuctionHouseFork(auction).initialize(
treasury,
NounsToken(token),
originalAuction.weth(),
originalAuction.timeBuffer(),
originalAuction.reservePrice(),
originalAuction.minBidIncrementPercentage(),
originalAuction.duration()
);
initDAO(governor, treasury, token, originalTimelock);
NounsDAOExecutorV2(payable(treasury)).initialize(governor, originalTimelock.delay());
emit DAODeployed(token, auction, governor, treasury);
}
/**
* @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 {
INounsDAOForkTokens originalDAO = INounsDAOForkTokens(payable(originalTimelock.admin()));
NounsDAOLogicV1Fork(governor).initialize(
treasury,
token,
initialVotingPeriod,
initialVotingDelay,
initialProposalThresholdBPS,
initialQuorumVotesBPS,
originalDAO.erc20TokensToIncludeInFork(),
block.timestamp + delayedGovernanceMaxDuration
);
}
/**
* @dev Used to prevent the 'Stack too deep' error in the main deploy function.
*/
function getOriginalTimelock(INounsDAOForkEscrow forkEscrow) internal view returns (NounsDAOExecutorV2) {
NounsToken originalToken = NounsToken(address(forkEscrow.nounsToken()));
return NounsDAOExecutorV2(payable(originalToken.owner()));
}
/**
* @dev Used to prevent the 'Stack too deep' error in the main deploy function.
*/
function getOriginalAuction(INounsDAOForkEscrow forkEscrow) internal view returns (NounsAuctionHouse) {
NounsToken originalToken = NounsToken(address(forkEscrow.nounsToken()));
return NounsAuctionHouse(originalToken.minter());
}
function getStartNounId(NounsAuctionHouse originalAuction) internal view returns (uint256) {
(uint256 nounId, , , , , ) = originalAuction.auction();
return nounId;
}
}