Skip to content

Commit

Permalink
feat: Add ChugSplash config parsing via Handlebars (ethereum-optimism…
Browse files Browse the repository at this point in the history
…#739)

* feat: Add ChugSplash config parsing with handlebars

* break out validation function

* fix: minor typo in config tests
  • Loading branch information
smartcontracts authored and ben-chain committed May 6, 2021
1 parent 660d6cb commit f1a9daa
Show file tree
Hide file tree
Showing 5 changed files with 486 additions and 1 deletion.
108 changes: 108 additions & 0 deletions packages/contracts/src/chugsplash/config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
/* Imports: External */
import * as Handlebars from 'handlebars'
import { ethers } from 'ethers'

type SolidityVariable =
| string
| number
| Array<SolidityVariable>
| {
[name: string]: SolidityVariable
}

export interface ChugSplashConfig {
contracts: {
[name: string]: {
address: string
source: string
variables?: {
[name: string]: SolidityVariable
}
}
}
}

/**
* Validates a ChugSplash config file.
* @param config Config file to validate.
*/
const validateChugSplashConfig = (config: ChugSplashConfig) => {
if (config.contracts === undefined) {
throw new Error('contracts field must be defined in ChugSplash config')
}

for (const [contractName, contractConfig] of Object.entries(
config.contracts
)) {
// Block people from accidentally using templates in contract names.
if (contractName.includes('{') || contractName.includes('}')) {
throw new Error(
`cannot use template strings in contract names: ${contractName}`
)
}

// Block people from accidentally using templates in contract names.
if (
contractConfig.source.includes('{') ||
contractConfig.source.includes('}')
) {
throw new Error(
`cannot use template strings in contract source names: ${contractConfig.source}`
)
}

// Make sure addresses are fixed and are actually addresses.
if (!ethers.utils.isAddress(contractConfig.address)) {
throw new Error(
`contract address is not a valid address: ${contractConfig.address}`
)
}
}
}

/**
* Parses a ChugSplash config file by replacing template values.
* @param config Unparsed config file to parse.
* @param env Environment variables to inject into the file.
* @return Parsed config file with template variables replaced.
*/
export const parseChugSplashConfig = (
config: ChugSplashConfig,
env: any = {}
): ChugSplashConfig => {
validateChugSplashConfig(config)

const contracts = {}
for (const [contractName, contractConfig] of Object.entries(
config.contracts
)) {
contracts[contractName] = contractConfig.address
}

return JSON.parse(
Handlebars.compile(JSON.stringify(config))({
env: new Proxy(env, {
get: (target, prop) => {
const val = target[prop]
if (val === undefined) {
throw new Error(
`attempted to access unknown env value: ${prop as any}`
)
}
return val
},
}),
contracts: new Proxy(contracts, {
get: (target, prop) => {
const val = target[prop]
if (val === undefined) {
throw new Error(
`attempted to access unknown contract: ${prop as any}`
)
}
return val
},
}),
})
)
}
1 change: 1 addition & 0 deletions packages/contracts/src/chugsplash/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './config'
1 change: 1 addition & 0 deletions packages/contracts/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ export * from './contract-defs'
export { getLatestStateDump, StateDump } from './contract-dumps'
export * from './contract-deployment'
export * from './predeploys'
export * from './chugsplash'
Loading

0 comments on commit f1a9daa

Please sign in to comment.