Skip to content

Commit

Permalink
feat(pg): add deployment artifact generation on the user's side
Browse files Browse the repository at this point in the history
  • Loading branch information
sam-goldman committed Nov 16, 2022
1 parent 27a5738 commit 8323afb
Show file tree
Hide file tree
Showing 8 changed files with 237 additions and 98 deletions.
8 changes: 8 additions & 0 deletions .changeset/chilly-planes-attack.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
'@chugsplash/plugins': minor
'@chugsplash/core': patch
'@chugsplash/demo': patch
'@chugsplash/executor': patch
---

Add deployment artifact generation on the user's side
6 changes: 4 additions & 2 deletions packages/core/src/actions/types.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { BigNumber } from 'ethers'

/**
* Possible action types.
*/
Expand Down Expand Up @@ -80,7 +82,7 @@ export type ChugSplashBundleState = {
status: ChugSplashBundleStatus
executions: boolean[]
merkleRoot: string
actionsExecuted: number
timeClaimed: number
actionsExecuted: BigNumber
timeClaimed: BigNumber
selectedExecutor: string
}
24 changes: 22 additions & 2 deletions packages/core/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import {
CHUGSPLASH_REGISTRY_PROXY_ADDRESS,
} from '@chugsplash/contracts'

import { ChugSplashConfig } from './config'

export const computeBundleId = (
bundleRoot: string,
bundleSize: number,
Expand Down Expand Up @@ -204,8 +206,26 @@ export const getChugSplashManagerImplementationAddress = async (
return managerImplementationAddress
}

export const ChugSplashLog = async (text: string, hide?: boolean) => {
if (!hide) {
export const chugsplashLog = (text: string, silent: boolean) => {
if (!silent) {
console.log(text)
}
}

export const displayDeploymentTable = (
parsedConfig: ChugSplashConfig,
silent: boolean
) => {
if (!silent) {
const deployments = {}
Object.entries(parsedConfig.contracts).forEach(
([referenceName, contractConfig], i) =>
(deployments[i + 1] = {
Reference: referenceName,
Contract: contractConfig.contract,
Address: contractConfig.address,
})
)
console.table(deployments)
}
}
4 changes: 4 additions & 0 deletions packages/demo/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
PRIVATE_KEY=<private key>
INFURA_API_KEY=<infura blockchain network api key>
IPFS_PROJECT_ID=<infura ipfs project id>
IPFS_API_KEY_SECRET=<infura ipfs api key secret>
58 changes: 58 additions & 0 deletions packages/plugins/src/hardhat/artifacts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import {
SolidityStorageLayout,
ChugSplashConfig,
CanonicalChugSplashConfig,
createDeploymentFolderForNetwork,
writeDeploymentArtifact,
} from '@chugsplash/core'
import { add0x, remove0x } from '@eth-optimism/core-utils'
import { ethers, utils } from 'ethers'
Expand Down Expand Up @@ -383,3 +385,59 @@ export const getArtifactsFromParsedCanonicalConfig = async (
}
return artifacts
}

export const createDeploymentArtifacts = async (
hre: any,
parsedConfig: ChugSplashConfig,
finalDeploymentTxnHash: string
) => {
createDeploymentFolderForNetwork(hre.network.name, hre.config.paths.deployed)

const provider = hre.ethers.provider

for (const [referenceName, contractConfig] of Object.entries(
parsedConfig.contracts
)) {
const artifact = getContractArtifact(contractConfig.contract)
const { sourceName, contractName, bytecode, abi } = artifact

const buildInfo = await getBuildInfo(sourceName, contractName)

const { constructorArgValues } = getConstructorArgs(
parsedConfig,
referenceName,
abi,
buildInfo.output,
sourceName,
contractName
)

const metadata =
buildInfo.output.contracts[sourceName][contractName].metadata
const { devdoc, userdoc } = JSON.parse(metadata).output

const deploymentArtifact = {
contractName,
address: contractConfig.address,
abi,
transactionHash: finalDeploymentTxnHash,
solcInputHash: buildInfo.id,
receipt: await provider.getTransactionReceipt(finalDeploymentTxnHash),
numDeployments: 1,
metadata,
args: constructorArgValues,
bytecode,
deployedBytecode: await provider.getCode(contractConfig.address),
devdoc,
userdoc,
storageLayout: await getStorageLayout(contractConfig.contract),
}

writeDeploymentArtifact(
hre.network.name,
hre.config.paths.deployed,
deploymentArtifact,
referenceName
)
}
}
22 changes: 16 additions & 6 deletions packages/plugins/src/hardhat/deployments.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,16 @@ import {
ChugSplashBundleStatus,
isProxyDeployed,
getChugSplashManagerProxyAddress,
ChugSplashLog,
chugsplashLog,
displayDeploymentTable,
} from '@chugsplash/core'
import { ChugSplashManagerABI, OWNER_BOND_AMOUNT } from '@chugsplash/contracts'
import { getChainId } from '@eth-optimism/core-utils'

import { getContractArtifact } from './artifacts'
import { createDeploymentArtifacts, getContractArtifact } from './artifacts'
import { loadParsedChugSplashConfig, writeHardhatSnapshotId } from './utils'
import { chugsplashCommitSubtask, chugsplashProposeSubtask } from './tasks'
import { monitorRemoteExecution } from './execution'

/**
* TODO
Expand Down Expand Up @@ -64,7 +66,7 @@ export const deployChugSplashConfig = async (

const parsedConfig = loadParsedChugSplashConfig(configPath)

ChugSplashLog(`Deploying: ${parsedConfig.options.projectName}`, silent)
chugsplashLog(`Deploying: ${parsedConfig.options.projectName}`, silent)

// Register the project with the signer as the owner. Once we've completed the deployment, we'll
// transfer ownership to the project owner specified in the config.
Expand Down Expand Up @@ -150,7 +152,17 @@ export const deployChugSplashConfig = async (
silent: true,
})

if (!remoteExecution) {
if (remoteExecution) {
const finalDeploymentTxnHash = await monitorRemoteExecution(
hre,
parsedConfig,
bundleId,
silent
)
await createDeploymentArtifacts(hre, parsedConfig, finalDeploymentTxnHash)
displayDeploymentTable(parsedConfig, silent)
chugsplashLog(`Deployed ${parsedConfig.options.projectName}.`, silent)
} else {
await hre.run('chugsplash-execute', {
chugSplashManager: ChugSplashManager,
bundleState,
Expand All @@ -160,8 +172,6 @@ export const deployChugSplashConfig = async (
silent,
})
}

ChugSplashLog(`Deployed: ${parsedConfig.options.projectName}`, silent)
}

export const getContract = async (
Expand Down
85 changes: 85 additions & 0 deletions packages/plugins/src/hardhat/execution.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import {
ChugSplashBundleState,
ChugSplashBundleStatus,
ChugSplashConfig,
chugsplashLog,
getChugSplashRegistry,
} from '@chugsplash/core'
import { HardhatRuntimeEnvironment } from 'hardhat/types'
import { SingleBar, Presets } from 'cli-progress'
import { ethers } from 'ethers'
import { ChugSplashManagerABI } from '@chugsplash/contracts'
import { sleep } from '@eth-optimism/core-utils'

export const monitorRemoteExecution = async (
hre: HardhatRuntimeEnvironment,
parsedConfig: ChugSplashConfig,
bundleId: string,
silent: boolean
): Promise<string> => {
const progressBar = new SingleBar({}, Presets.shades_classic)

const projectName = parsedConfig.options.projectName
const ChugSplashRegistry = getChugSplashRegistry(
hre.ethers.provider.getSigner()
)
const ChugSplashManager = new ethers.Contract(
await ChugSplashRegistry.projects(projectName),
ChugSplashManagerABI,
hre.ethers.provider
)

// Get the bundle state of the bundle ID.
let bundleState: ChugSplashBundleState = await ChugSplashManager.bundles(
bundleId
)

// Handle cases where the bundle is completed, cancelled, or not yet approved.
if (bundleState.status === ChugSplashBundleStatus.COMPLETED) {
chugsplashLog(`${projectName} has already been completed.`, silent)
return
} else if (bundleState.status === ChugSplashBundleStatus.CANCELLED) {
// Set the progress bar to be the number of executions that had occurred when the bundle was
// cancelled.
progressBar.start(
bundleState.executions.length,
bundleState.actionsExecuted
)
throw new Error(`${projectName} was cancelled.`)
} else if (bundleState.status !== ChugSplashBundleStatus.APPROVED) {
throw new Error(`${projectName} has not been approved for execution yet.`)
}

// If we make it to this point, we know that the given bundle is active.

// Set the status bar to display the number of actions executed so far.
progressBar.start(
bundleState.executions.length,
bundleState.actionsExecuted.toNumber()
)

while (bundleState.status === ChugSplashBundleStatus.APPROVED) {
// Get the current bundle state.
bundleState = await ChugSplashManager.bundles(bundleId)

// Update the progress bar.
progressBar.update(bundleState.actionsExecuted.toNumber())

// Wait for one second.
await sleep(1000)
}

if (bundleState.status === ChugSplashBundleStatus.COMPLETED) {
progressBar.update(bundleState.executions.length)
chugsplashLog('\n', silent)

// Get the `completeChugSplashBundle` transaction.
const [finalDeploymentEvent] = await ChugSplashManager.queryFilter(
ChugSplashManager.filters.ChugSplashBundleCompleted(bundleId)
)
const finalDeploymentTxnHash = finalDeploymentEvent.transactionHash
return finalDeploymentTxnHash
} else if (bundleState.status === ChugSplashBundleStatus.CANCELLED) {
throw new Error(`${projectName} was cancelled.`)
}
}
Loading

0 comments on commit 8323afb

Please sign in to comment.