Commit 90630336 authored by smartcontracts's avatar smartcontracts Committed by GitHub

feat(ctb): export ABI when building (#3067)

Updates the TypeScript build to also generate ABI objects that can be
imported on the client-side. Specifically necessary so that these ABIs
can be imported on the frontend where fs/glob is not available.
Co-authored-by: default avatarmergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
parent 7d68f82f
---
'@eth-optimism/contracts-bedrock': patch
---
Properly generates and exports ABI and artifact files that can be imported by client libraries
module.exports = {
extends: '../../.eslintrc.js',
ignorePatterns: ['src/contract-artifacts.ts'],
}
......@@ -7,3 +7,4 @@ coverage.out
deployments
broadcast
genesis.json
src/contract-artifacts.ts
......@@ -9,15 +9,16 @@
"dist/**/*.js",
"dist/**/*.d.ts",
"dist/types/*.ts",
"artifacts/src/**/*.json",
"artifacts/contracts/**/*.json",
"deployments/**/*.json",
"contracts/**/*.sol"
],
"scripts": {
"build:forge": "forge build",
"prebuild": "yarn ts-node scripts/verifyFoundryInstall.ts",
"build": "hardhat compile && yarn build:ts && yarn typechain",
"build": "hardhat compile && yarn autogen:artifacts && yarn build:ts && yarn typechain",
"build:ts": "tsc -p tsconfig.json",
"autogen:artifacts": "ts-node scripts/generate-artifacts.ts",
"deploy": "hardhat deploy",
"test": "yarn build:ts && forge test",
"gas-snapshot": "forge snapshot",
......@@ -64,6 +65,7 @@
"dotenv": "^16.0.0",
"ethereum-waffle": "^3.0.0",
"ethers": "^5.6.8",
"glob": "^7.1.6",
"hardhat-deploy": "^0.11.4",
"solhint": "^3.3.6",
"solhint-plugin-prettier": "^0.0.5",
......
import path from 'path'
import fs from 'fs'
import glob from 'glob'
/**
* Script for automatically generating a file which has a series of `require` statements for
* importing JSON contract artifacts. We do this to preserve browser compatibility.
*/
const main = async () => {
const contractArtifactsFolder = path.resolve(
__dirname,
`../artifacts/contracts`
)
const artifactPaths = glob
.sync(`${contractArtifactsFolder}/**/*[!.t].sol/**.json`)
.filter((match) => {
// Filter out the debug outputs.
return !match.endsWith('.dbg.json')
})
const content = `
/* eslint-disable @typescript-eslint/no-var-requires, no-empty */
/*
THIS FILE IS AUTOMATICALLY GENERATED.
DO NOT EDIT.
*/
${artifactPaths
.map((artifactPath) => {
// eslint-disable-next-line @typescript-eslint/no-var-requires
const artifact = require(artifactPath)
// handles the case - '\u' (\utils folder) is considered as an unicode encoded char
const pattern = /\\/g
const relPath = path
.relative(__dirname, artifactPath)
.replace(pattern, '/')
return `
let ${artifact.contractName}
try {
${artifact.contractName} = require('${relPath}')
} catch {}
`
})
.join('\n')}
export const getContractArtifact = (name: string): any => {
return {
${artifactPaths
.map((artifactPath) => {
// eslint-disable-next-line @typescript-eslint/no-var-requires
const artifact = require(artifactPath)
return `${artifact.contractName}`
})
.join(',\n')}
}[name]
}
`
fs.writeFileSync(
path.resolve(__dirname, `../src/contract-artifacts.ts`),
content
)
}
main()
import { ethers } from 'ethers'
/**
* Gets the hardhat artifact for the given contract name.
* Will throw an error if the contract artifact is not found.
*
* @param name Contract name.
* @returns The artifact for the given contract name.
*/
export const getContractDefinition = (name: string): any => {
// We import this using `require` because hardhat tries to build this file when compiling
// the contracts, but we need the contracts to be compiled before the contract-artifacts.ts
// file can be generated.
// eslint-disable-next-line @typescript-eslint/no-var-requires
const { getContractArtifact } = require('./contract-artifacts')
const artifact = getContractArtifact(name)
if (artifact === undefined) {
throw new Error(`Unable to find artifact for contract: ${name}`)
}
return artifact
}
/**
* Gets an ethers Interface instance for the given contract name.
*
* @param name Contract name.
* @returns The interface for the given contract name.
*/
export const getContractInterface = (name: string): ethers.utils.Interface => {
const definition = getContractDefinition(name)
return new ethers.utils.Interface(definition.abi)
}
/**
* Gets an ethers ContractFactory instance for the given contract name.
*
* @param name Contract name.
* @param signer The signer for the ContractFactory to use.
* @returns The contract factory for the given contract name.
*/
export const getContractFactory = (
name: string,
signer?: ethers.Signer
): ethers.ContractFactory => {
const definition = getContractDefinition(name)
const contractInterface = getContractInterface(name)
return new ethers.ContractFactory(
contractInterface,
definition.bytecode,
signer
)
}
export * from './constants'
export * from './contract-defs'
......@@ -5,5 +5,5 @@
"outDir": "./dist"
},
"exclude": ["hardhat.config.ts", "deploy", "tasks", "test"],
"include": ["src/**/*", "scripts/differential-testing.ts"]
"include": ["src/**/*", "scripts/**/*"]
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment