-
Notifications
You must be signed in to change notification settings - Fork 45
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
deploy: Delta production deployment scripts (#631)
* hardhat: Fix .env files * hardhat: Migrate to newer etherscan verify plugin * tasks: Create task to verify all deployed contracts * doc: Add instructions on how to deploy to a network * deploy: Move treasury deploy to deploy_contracts * deploy: Update deployer to support delta deployment - Allows deploying proxy without registering them on controller - Fixes the names of the deployments that are saved/overridden - Deploying only the target will not set the "main" deployment file - Deploying with a proxy will not set the ManagerProxy deployment * deploy: Create delta deployment script * deploy: Allow only governor to execute treasury proposals The Governor already exposes an execute() function that will call the timelock (treasury) internally, so we don't need to expose the treasury directly to calls by anyone. * utils: Split deployAndRegister func from ContractDeployer * deploy,doc: Address other PR comments * deploy: Fix deploy_poll script It doesnt want registration so just call deploy() * tasks: Create task to renounce admin role post-deploy Good to already have pre-tested scripts for the deployment steps. * doc: Add docs on delta deploy steps * doc: Address comments on deploy steps doc
- Loading branch information
Showing
17 changed files
with
1,010 additions
and
190 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,207 @@ | ||
import {HardhatRuntimeEnvironment} from "hardhat/types" | ||
import {DeployFunction} from "hardhat-deploy/types" | ||
|
||
import ContractDeployer from "../utils/deployer" | ||
import {ethers} from "hardhat" | ||
import {BondingManager, LivepeerGovernor, Treasury} from "../typechain" | ||
import getNetworkConfig from "./migrations.config" | ||
import {contractId} from "../utils/helpers" | ||
|
||
const PROD_NETWORKS = ["mainnet", "arbitrumMainnet"] | ||
|
||
const isProdNetwork = (name: string): boolean => { | ||
return PROD_NETWORKS.indexOf(name) > -1 | ||
} | ||
|
||
// Returns a reference to the given contract in the format used by the governor-scripts repo (e.g. | ||
// "ADDRESSES.arbitrumMainnet.controller"). Notice that on the serialized JSON, this will come out as a string while in | ||
// the governance script it should be de-stringified (remove quotes) to reference an imported ADDRESS object. | ||
const contractAddressRef = (network: string, name: string) => { | ||
const lowerName = name[0].toLowerCase() + name.slice(1) | ||
return `ADDRESSES.${network}.${lowerName}` | ||
} | ||
|
||
// Returns a governance action spec in the format expected by the governor-scripts to call the setContractInfo function | ||
// on the controller to register a contract in the protocol. | ||
const setContractInfoAction = ( | ||
network: string, | ||
gitCommitHash: string, | ||
name: string | ||
) => ({ | ||
target: contractAddressRef(network, "Controller"), | ||
value: "0", | ||
contract: "Controller", | ||
name: "setContractInfo", | ||
params: [contractId(name), contractAddressRef(network, name), gitCommitHash] | ||
}) | ||
|
||
// Deploys the Livepeer Delta protocol upgrade from the previous version (962107f). This deploys only the targets | ||
// for already existing contracts, and skips registering them in the controller in case it's a production network. | ||
const func: DeployFunction = async function(hre: HardhatRuntimeEnvironment) { | ||
const {deployments, getNamedAccounts} = hre // Get the deployments and getNamedAccounts which are provided by hardhat-deploy | ||
|
||
const network = hre.network.name | ||
const config = getNetworkConfig(network) | ||
|
||
const {deployer} = await getNamedAccounts() // Fetch named accounts from hardhat.config.ts | ||
|
||
const contractDeployer = new ContractDeployer(deployer, deployments) | ||
const controller = await contractDeployer.fetchDeployedController() | ||
|
||
// on prod networks, deploy contracts here but registration is done later through governance | ||
// on test networks, the deployer must also be the controller owner so we can register here | ||
const skipRegister = isProdNetwork(network) | ||
const deploy = skipRegister ? | ||
contractDeployer.deploy.bind(contractDeployer) : | ||
contractDeployer.deployAndRegister.bind(contractDeployer) | ||
|
||
const gitCommitHash = await contractDeployer.getGitHeadCommitHash() | ||
const governanceActions = [] | ||
|
||
// Deploy contracts | ||
await deploy({ | ||
contract: "BondingVotes", | ||
name: "BondingVotes", | ||
args: [controller.address], | ||
proxy: true | ||
}) | ||
governanceActions.push( | ||
setContractInfoAction(network, gitCommitHash, "BondingVotesTarget"), | ||
setContractInfoAction(network, gitCommitHash, "BondingVotes") | ||
) | ||
|
||
const treasury = await deploy({ | ||
contract: "Treasury", | ||
name: "Treasury", | ||
args: [], | ||
proxy: false | ||
}) | ||
governanceActions.push( | ||
setContractInfoAction(network, gitCommitHash, "Treasury") | ||
) | ||
|
||
const Treasury: Treasury = await ethers.getContractAt( | ||
"Treasury", | ||
treasury.address | ||
) | ||
|
||
// We should already initialize the treasury since it's not a proxy | ||
await Treasury.initialize( | ||
config.treasury.minDelay, | ||
[], // governor will be added as a proposer later | ||
[], // governor will be added as an executor later | ||
deployer // temporary admin role for deployer | ||
).then(tx => tx.wait()) | ||
|
||
const livepeerGovernor = await deploy({ | ||
contract: "LivepeerGovernor", | ||
name: "LivepeerGovernor", | ||
args: [controller.address], | ||
proxy: true | ||
}) | ||
governanceActions.push( | ||
setContractInfoAction(network, gitCommitHash, "LivepeerGovernorTarget"), | ||
setContractInfoAction(network, gitCommitHash, "LivepeerGovernor") | ||
) | ||
|
||
const llDeployment = await deployments.get("SortedDoublyLL") | ||
|
||
await deploy({ | ||
contract: "BondingManager", | ||
name: "BondingManagerTarget", | ||
libraries: { | ||
SortedDoublyLL: llDeployment.address | ||
}, | ||
args: [controller.address], | ||
proxy: false // we're deploying the Target directly, so proxy is false | ||
}) | ||
governanceActions.push( | ||
setContractInfoAction(network, gitCommitHash, "BondingManagerTarget") | ||
) | ||
|
||
// Setup/initialize contracts (or print the required governance actions) | ||
|
||
// Grant proposer and executor roles to governor and renounce deployer admin role | ||
const roles = { | ||
proposer: await Treasury.PROPOSER_ROLE(), | ||
canceller: await Treasury.CANCELLER_ROLE(), | ||
executor: await Treasury.EXECUTOR_ROLE(), | ||
admin: await Treasury.TIMELOCK_ADMIN_ROLE() | ||
} | ||
for (const role of [roles.proposer, roles.canceller, roles.executor]) { | ||
await Treasury.grantRole(role, livepeerGovernor.address).then(tx => | ||
tx.wait() | ||
) | ||
} | ||
|
||
const LivepeerGovernor: LivepeerGovernor = await ethers.getContractAt( | ||
"LivepeerGovernor", | ||
livepeerGovernor.address | ||
) | ||
const governorInitParams = [ | ||
config.livepeerGovernor.initialVotingDelay, | ||
config.livepeerGovernor.initialVotingPeriod, | ||
config.livepeerGovernor.initialProposalThreshold, | ||
config.livepeerGovernor.initialQuorum, | ||
config.livepeerGovernor.quota | ||
] as Parameters<typeof LivepeerGovernor.initialize> | ||
|
||
if (!skipRegister) { | ||
await LivepeerGovernor.initialize(...governorInitParams).then(tx => | ||
tx.wait() | ||
) | ||
} else { | ||
governanceActions.push({ | ||
target: contractAddressRef(network, "LivepeerGovernor"), | ||
value: "0", | ||
contract: "LivepeerGovernor", | ||
name: "initialize", | ||
params: governorInitParams | ||
}) | ||
} | ||
|
||
if (!skipRegister) { | ||
// We need to refetch the BondingManager contract as we only deploy the Target above | ||
const bondingManager = await deployments.get("BondingManager") | ||
const BondingManager: BondingManager = await ethers.getContractAt( | ||
"BondingManager", | ||
bondingManager.address | ||
) | ||
|
||
await BondingManager.setTreasuryRewardCutRate( | ||
config.bondingManager.treasuryRewardCutRate | ||
).then(tx => tx.wait()) | ||
await BondingManager.setTreasuryBalanceCeiling( | ||
config.bondingManager.treasuryBalanceCeiling | ||
).then(tx => tx.wait()) | ||
} else { | ||
governanceActions.push( | ||
{ | ||
target: contractAddressRef(network, "BondingManager"), | ||
value: "0", | ||
contract: "BondingManager", | ||
name: "setTreasuryRewardCutRate", | ||
params: [config.bondingManager.treasuryRewardCutRate] | ||
}, | ||
{ | ||
target: contractAddressRef(network, "BondingManager"), | ||
value: "0", | ||
contract: "BondingManager", | ||
name: "setTreasuryBalanceCeiling", | ||
params: [config.bondingManager.treasuryBalanceCeiling] | ||
} | ||
) | ||
} | ||
|
||
// Helper print out to validate the pending governance actions that will be required by the protocol owner | ||
if (skipRegister) { | ||
console.log("Pending governance actions:") | ||
console.log(JSON.stringify(governanceActions, null, 2)) | ||
} | ||
|
||
console.log("Deployer must renounce ADMIN role from the Treasury with:") | ||
console.log(`npx hardhat treasury-renounce-admin-role --network ${network}`) | ||
} | ||
|
||
func.tags = ["DELTA_UPGRADE"] | ||
export default func |
Oops, something went wrong.