• Mark Tyneway's avatar
    contracts: add inspect hh task (#3301) · 0c2719f8
    Mark Tyneway authored
    This hardhat task mirrors functionality of `forge inspect`
    where you can pass a contract name and a compiler output field
    and it will print that field for you. This will be useful for
    building sets of `storageLayout`s and `methodIdentifiers` to
    compare against the bedrock contracts.
    
    Example usage:
    
    ```
    $ npx hardhat inspect AddressDictator storageLayout
    ```
    
    Where `AddressDictator` can be any contract in the package
    and `storageLayout` can be one of the following:
    
    - abi
    - bytecode
    - deployedBytecode
    - storageLayout
    - methodIdentifiers
    
    This is one of the more useful features of foundry so porting it
    to hardhat will make storageLayout inspections much easier.
    Co-authored-by: default avatarmergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
    0c2719f8
inspect.ts 2.24 KB
import { task } from 'hardhat/config'
import * as types from 'hardhat/internal/core/params/argumentTypes'

const getFullyQualifiedName = (
  sourceName: string,
  contractName: string
): string => {
  return `${sourceName}:${contractName}`
}

task('inspect')
  .addPositionalParam(
    'contractName',
    'Name of the contract to inspect',
    undefined,
    types.string,
    false
  )
  .addPositionalParam(
    'field',
    'Compiler output field to inspect',
    undefined,
    types.string,
    false
  )
  .setAction(async (args, hre) => {
    const artifact = await hre.artifacts.readArtifact(args.contractName)
    const fqn = getFullyQualifiedName(
      artifact.sourceName,
      artifact.contractName
    )
    const buildInfo = await hre.artifacts.getBuildInfo(fqn)
    const info =
      buildInfo.output.contracts[artifact.sourceName][artifact.contractName]
    if (!info) {
      throw new Error(`Cannot find build info for ${fqn}`)
    }

    try {
      switch (args.field) {
        case 'abi': {
          const abi = info.abi
          console.log(JSON.stringify(abi, null, 2))
          break
        }
        case 'bytecode': {
          const bytecode = info.evm.bytecode.object
          console.log('0x' + bytecode)
          break
        }
        case 'deployedBytecode': {
          const bytecode = info.evm.deployedBytecode.object
          console.log('0x' + bytecode)
          break
        }
        case 'storageLayout': {
          const storageLayout = (info as any).storageLayout
          console.log(JSON.stringify(storageLayout, null, 2))
          break
        }
        case 'methodIdentifiers': {
          const methodIdentifiers = info.evm.methodIdentifiers
          console.log(JSON.stringify(methodIdentifiers, null, 2))
          break
        }
        default: {
          console.log(
            JSON.stringify(
              {
                error: `Unsupported field ${args.field}`,
              },
              null,
              2
            )
          )
          break
        }
      }
    } catch (e) {
      console.log(
        JSON.stringify(
          {
            error: `Cannot find ${args.field}, be sure to enable it in compiler settings`,
          },
          null,
          2
        )
      )
    }
  })