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
171
172
173
174
175
176
177
178
179
180
181
182
183
import { task, types } from 'hardhat/config'
import { ethers } from 'ethers'
import { LedgerSigner } from '@ethersproject/hardware-wallets'
import dotenv from 'dotenv'
import { prompt } from '../src/prompt'
dotenv.config()
// Hardcode the expected addresse
const addresses = {
governanceToken: '0x4200000000000000000000000000000000000042',
}
task('deploy-token', 'Deploy governance token and its mint manager contracts')
.addParam('mintManagerOwner', 'Owner of the mint manager')
.addOptionalParam('useLedger', 'User ledger hardware wallet as signer')
.addOptionalParam(
'ledgerTokenDeployerPath',
'Ledger key derivation path for the token deployer account',
ethers.utils.defaultPath,
types.string
)
.addParam(
'pkDeployer',
'Private key for main deployer account',
process.env.PRIVATE_KEY_DEPLOYER
)
.addOptionalParam(
'pkTokenDeployer',
'Private key for the token deployer account',
process.env.PRIVATE_KEY_TOKEN_DEPLOYER
)
.setAction(async (args, hre) => {
console.log('Deploying token to', hre.network.name, 'network')
// There cannot be two ledgers at the same time
let tokenDeployer
// Deploy the token
if (args.useLedger) {
// Token is deployed to a system address at `0x4200000000000000000000000000000000000042`
// For that a dedicated deployer account is used
tokenDeployer = new LedgerSigner(
hre.ethers.provider,
'default',
args.ledgerTokenDeployerPath
)
} else {
tokenDeployer = new hre.ethers.Wallet(args.pkTokenDeployer).connect(
hre.ethers.provider
)
}
// Create the MintManager Deployer
const deployer = new hre.ethers.Wallet(args.pkDeployer).connect(
hre.ethers.provider
)
// Get the sizes of the bytecode to check if the contracts
// have already been deployed. Useful for an error partway through
// the script
const governanceTokenCode = await hre.ethers.provider.getCode(
addresses.governanceToken
)
const addrTokenDeployer = await tokenDeployer.getAddress()
console.log(`Using token deployer: ${addrTokenDeployer}`)
const tokenDeployerBalance = await tokenDeployer.getBalance()
if (tokenDeployerBalance.eq(0)) {
throw new Error(`Token deployer has no balance`)
}
console.log(`Token deployer balance: ${tokenDeployerBalance.toString()}`)
const nonceTokenDeployer = await tokenDeployer.getTransactionCount()
console.log(`Token deployer nonce: ${nonceTokenDeployer}`)
const GovernanceToken = await hre.ethers.getContractFactory(
'GovernanceToken'
)
let governanceToken = GovernanceToken.attach(
addresses.governanceToken
).connect(tokenDeployer)
if (nonceTokenDeployer === 0 && governanceTokenCode === '0x') {
await prompt('Ready to deploy. Does everything look OK?')
// Deploy the GovernanceToken
governanceToken = await GovernanceToken.connect(tokenDeployer).deploy()
const tokenReceipt = await governanceToken.deployTransaction.wait()
console.log('GovernanceToken deployed to:', tokenReceipt.contractAddress)
if (tokenReceipt.contractAddress !== addresses.governanceToken) {
console.log(
`Expected governance token address ${addresses.governanceToken}`
)
console.log(`Got ${tokenReceipt.contractAddress}`)
throw new Error(`Fatal error! Mismatch of governance token address`)
}
} else if (nonceTokenDeployer !== 0 && governanceTokenCode === '0x') {
throw new Error(
`Nonce is ${nonceTokenDeployer} without governance token deployed`
)
} else {
console.log(
`GovernanceToken already deployed at ${addresses.governanceToken}, skipping`
)
console.log(`Deployer nonce: ${nonceTokenDeployer}`)
console.log(`Code size: ${governanceTokenCode.length}`)
}
const { mintManagerOwner } = args
// Do the deployer things
console.log('Deploying MintManager')
const addr = await deployer.getAddress()
console.log(`Using MintManager deployer: ${addr}`)
const deployerBalance = await deployer.getBalance()
if (deployerBalance.eq(0)) {
throw new Error('Deployer has no balance')
}
console.log(`Deployer balance: ${deployerBalance.toString()}`)
const deployerNonce = await deployer.getTransactionCount()
console.log(`Deployer nonce: ${deployerNonce}`)
await prompt('Does this look OK?')
const MintManager = await hre.ethers.getContractFactory('MintManager')
// Deploy the MintManager
console.log(
`Deploying MintManager with (${mintManagerOwner}, ${addresses.governanceToken})`
)
const mintManager = await MintManager.connect(deployer).deploy(
mintManagerOwner,
addresses.governanceToken
)
const receipt = await mintManager.deployTransaction.wait()
console.log(`Deployed mint manager to ${receipt.contractAddress}`)
let mmOwner = await mintManager.owner()
const currTokenOwner = await governanceToken
.attach(addresses.governanceToken)
.owner()
console.log(
'About to transfer ownership of the token to the mint manager! This is irreversible.'
)
console.log(`Current token owner: ${currTokenOwner}`)
console.log(`Mint manager address: ${mintManager.address}`)
console.log(`Mint manager owner: ${mmOwner}`)
await prompt('Is this OK?')
console.log('Transferring ownership...')
// Transfer ownership of the token to the MintManager instance
const tx = await governanceToken
.attach(addresses.governanceToken)
.transferOwnership(mintManager.address)
await tx.wait()
console.log(
`Transferred ownership of governance token to ${mintManager.address}`
)
console.log('MintManager deployed to:', receipt.contractAddress)
console.log('MintManager owner set to:', mintManagerOwner)
console.log(
'MintManager governanceToken set to:',
addresses.governanceToken
)
console.log('### Token deployment complete ###')
const tokOwner = await governanceToken
.attach(addresses.governanceToken)
.owner()
if (tokOwner !== mintManager.address) {
throw new Error(`GovernanceToken owner not set correctly`)
}
// Check that the deployment went as expected
const govToken = await mintManager.governanceToken()
if (govToken !== addresses.governanceToken) {
throw new Error(`MintManager governance token not set correctly`)
}
mmOwner = await mintManager.owner()
if (mmOwner !== mintManagerOwner) {
throw new Error(`MintManager owner not set correctly`)
}
console.log('Validated MintManager config')
})