Skip to content

Commit

Permalink
utils: Split deployAndRegister func from ContractDeployer
Browse files Browse the repository at this point in the history
  • Loading branch information
victorges committed Oct 10, 2023
1 parent ff30c77 commit fccc671
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 78 deletions.
2 changes: 1 addition & 1 deletion deploy/deploy_contracts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,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
22 changes: 10 additions & 12 deletions deploy/deploy_delta_upgrade.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,29 +39,27 @@ const setContractInfoAction = (
// 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 {deploy} = deployments // the deployments object itself contains the deploy function

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 contractDeployer = new ContractDeployer(
deploy,
deployer,
deployments,
skipRegister
)
const controller = await contractDeployer.fetchDeployedController()
const deploy = skipRegister ?
contractDeployer.deploy.bind(contractDeployer) :
contractDeployer.deployAndRegister.bind(contractDeployer)

const gitCommitHash = await contractDeployer.getGitHeadCommitHash()
const governanceActions = []

// Deploy contracts
await contractDeployer.deployAndRegister({
await deploy({
contract: "BondingVotes",
name: "BondingVotes",
args: [controller.address],
Expand All @@ -72,7 +70,7 @@ const func: DeployFunction = async function(hre: HardhatRuntimeEnvironment) {
setContractInfoAction(network, gitCommitHash, "BondingVotes")
)

const treasury = await contractDeployer.deployAndRegister({
const treasury = await deploy({
contract: "Treasury",
name: "Treasury",
args: [],
Expand All @@ -95,7 +93,7 @@ const func: DeployFunction = async function(hre: HardhatRuntimeEnvironment) {
deployer // temporary admin role for deployer
).then(tx => tx.wait())

const livepeerGovernor = await contractDeployer.deployAndRegister({
const livepeerGovernor = await deploy({
contract: "LivepeerGovernor",
name: "LivepeerGovernor",
args: [controller.address],
Expand All @@ -108,7 +106,7 @@ const func: DeployFunction = async function(hre: HardhatRuntimeEnvironment) {

const llDeployment = await deployments.get("SortedDoublyLL")

await contractDeployer.deployAndRegister({
await deploy({
contract: "BondingManager",
name: "BondingManagerTarget",
libraries: {
Expand Down
4 changes: 2 additions & 2 deletions deploy/deploy_poll.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@ import ContractDeployer from "../utils/deployer"

const func: DeployFunction = async function(hre: HardhatRuntimeEnvironment) {
const {deployments, getNamedAccounts} = hre // Get the deployments and getNamedAccounts which are provided by hardhat-deploy
const {deploy, get} = deployments // the deployments object itself contains the deploy function
const {get} = deployments // the deployments object itself contains the deploy function

const {deployer} = await getNamedAccounts() // Fetch named accounts from hardhat.config.ts

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

const bondingManager = await get("BondingManager")

Expand Down
119 changes: 56 additions & 63 deletions utils/deployer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,39 +3,28 @@ import childProcess from "child_process"
const exec = util.promisify(childProcess.exec)

import {ethers} from "hardhat"
import {
DeployOptions,
DeployResult,
DeploymentsExtension
} from "hardhat-deploy/types"
import {DeployResult, DeploymentsExtension} from "hardhat-deploy/types"
import {deployments} from "hardhat"
import {Controller} from "../typechain"
import {Libraries} from "hardhat/types"

export type DeployConfig = {
contract: string
name: string
proxy?: boolean
args: Array<any>
libraries?: Libraries | undefined
}

export default class ContractDeployer {
deploy: (name: string, options: DeployOptions) => Promise<DeployResult>
deployer: string
deployments: DeploymentsExtension
controller: Controller | undefined

/**
* skipRegister is used to skip the registration on the protocol controller (`setContractInfo`) of contracts
* deployed with this deployer instance. It is used when the deployer account is not the controller owner, which is
* the case in prod networks. In production, the registration has to be done through proceeding governance actions.
*/
readonly skipRegister: boolean

constructor(
deploy: (name: string, options: DeployOptions) => Promise<DeployResult>,
deployer: string,
deployments: DeploymentsExtension,
skipRegister = false
) {
this.deploy = deploy
constructor(deployer: string, deployments: DeploymentsExtension) {
this.deployer = deployer
this.deployments = deployments
this.controller = undefined
this.skipRegister = skipRegister
}

async getGitHeadCommitHash(): Promise<string> {
Expand All @@ -50,22 +39,13 @@ export default class ContractDeployer {
return ethers.utils.solidityKeccak256(["string"], [name])
}

async register(name: string, address: string) {
const gitHash = await this.getGitHeadCommitHash()
await (
await this.controller?.setContractInfo(
this.contractId(name),
address,
gitHash
)
)?.wait()
}

async deployController(): Promise<Controller> {
if (this.controller && (await deployments.get("Controller"))) {
console.log("Controller already deployed")
} else {
const controller = await this.deploy("Controller", {
const {deploy} = this.deployments // the deployments object itself contains the deploy function

const controller = await deploy("Controller", {
from: this.deployer, // msg.sender overwrite, use named account
args: [], // constructor arguments
log: true // display the address and gas used in the console (not when run in test though)
Expand All @@ -87,34 +67,46 @@ export default class ContractDeployer {
return this.controller
}

async deployAndRegister(config: {
contract: string
name: string
proxy?: boolean
args: Array<any>
libraries?: Libraries | undefined
}): Promise<DeployResult> {
const {contract, name, proxy, args, libraries} = config
async deployAndRegister(config: DeployConfig): Promise<DeployResult> {
const {name, proxy} = config

const shouldRegister = this.controller && !this.skipRegister
const gitHash = await this.getGitHeadCommitHash()
if (!this.controller) {
throw new Error("Controller not initialized for registration")
}

const deploy = await this.deploy(config)

if (proxy) {
// deploy function only returns the proxy deployment in this case, so fetch the deployed target info
const targetName = `${name}Target`
const target = await this.deployments.get(targetName)
if (!target) {
throw new Error(`${targetName} not found`)
}

// target has to be registered with a Target suffix
await this.register(targetName, target.address)
}

// proxy gets registered as the actual contract name
await this.register(name, deploy.address)

return deploy
}

async deploy(config: DeployConfig) {
const {contract, name, proxy, args, libraries} = config
const {deploy} = this.deployments // the deployments object itself contains the deploy function

// if there's no proxy, the target is just the contract itself
const targetName = proxy ? `${name}Target` : name
const target = await this.deploy(targetName, {
const target = await deploy(targetName, {
contract,
from: this.deployer,
log: true,
args: [...args],
libraries: libraries
})
if (shouldRegister) {
await this.controller!.setContractInfo(
this.contractId(targetName),
target.address,
gitHash
).then(tx => tx.wait())
}

if (!proxy) {
return target
Expand All @@ -124,26 +116,27 @@ export default class ContractDeployer {
}

// proxy == true, proceed with proxy deployment and registration as the actual contract `name`
const managerProxy = await this.deploy(name, {
const managerProxy = await deploy(name, {
contract: "ManagerProxy",
from: this.deployer,
log: true,
args: [this.controller?.address, this.contractId(targetName)]
args: [this.controller.address, this.contractId(targetName)]
})

if (shouldRegister) {
await this.controller
.setContractInfo(
this.contractId(name),
managerProxy.address,
gitHash
)
.then(tx => tx.wait())
}

// additionally, save the proxy deployment with a "Proxy" suffix
await deployments.save(`${name}Proxy`, managerProxy)

return managerProxy
}

async register(name: string, address: string) {
const gitHash = await this.getGitHeadCommitHash()
await (
await this.controller?.setContractInfo(
this.contractId(name),
address,
gitHash
)
)?.wait()
}
}

0 comments on commit fccc671

Please sign in to comment.