Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

deploy: Delta production deployment scripts #631

Merged
merged 14 commits into from
Oct 11, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 78 additions & 2 deletions deploy/deploy_contracts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ import {
RoundsManager,
TicketBroker,
LivepeerToken,
Governor
Governor,
LivepeerGovernor,
Treasury
} from "../typechain"

import ContractDeployer from "../utils/deployer"
Expand Down Expand Up @@ -63,7 +65,7 @@ const func: DeployFunction = async function(hre: HardhatRuntimeEnvironment) {

const config = getNetworkConfig(hre.network.name)

const contractDeployer = new ContractDeployer(deploy, deployer, deployments)
const contractDeployer = new ContractDeployer(deployer, deployments)

const Controller: Controller = await contractDeployer.deployController()

Expand Down Expand Up @@ -159,6 +161,8 @@ const func: DeployFunction = async function(hre: HardhatRuntimeEnvironment) {
proxy: true,
args: [Controller.address]
})
// tests expect it to be saved as AdjustableRoundsManager as well
await deployments.save("AdjustableRoundsManager", roundsManager)
yondonfu marked this conversation as resolved.
Show resolved Hide resolved
} else {
roundsManager = await contractDeployer.deployAndRegister({
contract: "RoundsManager",
Expand Down Expand Up @@ -212,6 +216,21 @@ const func: DeployFunction = async function(hre: HardhatRuntimeEnvironment) {
await (await Governor.stage(transferOwnershipUpdate, 0)).wait()
await (await Governor.execute(transferOwnershipUpdate)).wait()

// Treasury (LivepeerGovernor)

const treasury = await contractDeployer.deployAndRegister({
contract: "Treasury",
name: "Treasury",
args: []
})

const livepeerGovernor = await contractDeployer.deployAndRegister({
contract: "LivepeerGovernor",
name: "LivepeerGovernor",
args: [Controller.address],
proxy: true
})

// Set BondingManager parameters
const BondingManager: BondingManager = (await ethers.getContractAt(
"BondingManager",
Expand All @@ -229,6 +248,21 @@ const func: DeployFunction = async function(hre: HardhatRuntimeEnvironment) {
)
).wait()

if (config.bondingManager.treasuryRewardCutRate) {
await (
await BondingManager.setTreasuryRewardCutRate(
config.bondingManager.treasuryRewardCutRate
)
).wait()
}
if (config.bondingManager.treasuryBalanceCeiling) {
await (
await BondingManager.setTreasuryBalanceCeiling(
config.bondingManager.treasuryBalanceCeiling
)
).wait()
}

// Set RoundsManager parameters
const RoundsManager: RoundsManager = (await ethers.getContractAt(
"RoundsManager",
Expand Down Expand Up @@ -259,6 +293,48 @@ const func: DeployFunction = async function(hre: HardhatRuntimeEnvironment) {
}
}

// Initialize Treasury and LivepeerGovernor

const Treasury: Treasury = await ethers.getContractAt(
"Treasury",
treasury.address
)

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: LivepeerGovernor = await ethers.getContractAt(
"LivepeerGovernor",
livepeerGovernor.address
)

await LivepeerGovernor.initialize(
config.livepeerGovernor.initialVotingDelay,
config.livepeerGovernor.initialVotingPeriod,
config.livepeerGovernor.initialProposalThreshold,
config.livepeerGovernor.initialQuorum,
config.livepeerGovernor.quota
).then(tx => tx.wait())

// Now 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()
)
}

await Treasury.renounceRole(roles.admin, deployer).then(tx => tx.wait())

// Set TicketBroker parameters
const Broker: TicketBroker = (await ethers.getContractAt(
"TicketBroker",
Expand Down
207 changes: 207 additions & 0 deletions deploy/deploy_delta_upgrade.ts
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 = []
victorges marked this conversation as resolved.
Show resolved Hide resolved

// 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
Loading
Loading