hardhat/types#Artifact TypeScript Examples

The following examples show how to use hardhat/types#Artifact. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: utils.ts    From hardhat-deploy with MIT License 7 votes vote down vote up
export async function getArtifactFromFolders(
  name: string,
  folderPaths: string[]
): Promise<Artifact | ExtendedArtifact | undefined> {
  for (const onepath of folderPaths) {
    const artifacts = new Artifacts(onepath);
    let artifact = getOldArtifactSync(name, onepath);
    if (!artifact) {
      try {
        artifact = artifacts.readArtifactSync(name);
      } catch (e) {
        const hardhatError = e as HardhatError;
        if (
          hardhatError.number &&
          hardhatError.number == ERRORS.ARTIFACTS.MULTIPLE_FOUND.number
        ) {
          throw e;
        }
      }
    }
    if (artifact) {
      return artifact;
    }
  }
}
Example #2
Source File: contract.ts    From balancer-v2-monorepo with GNU General Public License v3.0 6 votes vote down vote up
export async function getArtifact(contract: string): Promise<Artifact> {
  let artifactsPath: string;
  if (!contract.includes('/')) {
    artifactsPath = path.resolve('./artifacts');
  } else {
    const packageName = `@balancer-labs/${contract.split('/')[0]}`;
    const packagePath = path.dirname(require.resolve(`${packageName}/package.json`));
    artifactsPath = `${packagePath}/artifacts`;
  }

  const artifacts = new Artifacts(artifactsPath);
  return artifacts.readArtifact(contract.split('/').slice(-1)[0]);
}
Example #3
Source File: contract.ts    From balancer-v2-monorepo with GNU General Public License v3.0 6 votes vote down vote up
// From https://github.com/nomiclabs/hardhat/issues/611#issuecomment-638891597, temporary workaround until
// https://github.com/nomiclabs/hardhat/issues/1716 is addressed.
function linkBytecode(artifact: Artifact, libraries: Dictionary<string>): string {
  let bytecode = artifact.bytecode;

  for (const [, fileReferences] of Object.entries(artifact.linkReferences)) {
    for (const [libName, fixups] of Object.entries(fileReferences)) {
      const addr = libraries[libName];
      if (addr === undefined) {
        continue;
      }

      for (const fixup of fixups) {
        bytecode =
          bytecode.substr(0, 2 + fixup.start * 2) +
          addr.substr(2) +
          bytecode.substr(2 + (fixup.start + fixup.length) * 2);
      }
    }
  }

  return bytecode;
}
Example #4
Source File: utils.ts    From hardhat-deploy with MIT License 6 votes vote down vote up
// TODO
// const solcInputMetadataCache: Record<string,
// const buildInfoCache
// const hashCache: Record<string, string> = {};

export async function getExtendedArtifactFromFolders(
  name: string,
  folderPaths: string[]
): Promise<ExtendedArtifact | undefined> {
  for (const folderPath of folderPaths) {
    const artifacts = new Artifacts(folderPath);
    let artifact = getOldArtifactSync(name, folderPath);
    if (!artifact && (await artifacts.artifactExists(name))) {
      const hardhatArtifact: Artifact = await artifacts.readArtifact(name);
      // check if name is already a fullyQualifiedName
      let fullyQualifiedName = name;
      let contractName = name;
      if (!fullyQualifiedName.includes(':')) {
        fullyQualifiedName = `${hardhatArtifact.sourceName}:${name}`;
      } else {
        contractName = fullyQualifiedName.split(':')[1];
      }
      // TODO try catch ? in case debug file is missing
      const buildInfo = await artifacts.getBuildInfo(fullyQualifiedName);
      if (buildInfo) {
        const solcInput = JSON.stringify(buildInfo.input, null, '  ');
        const solcInputHash = Buffer.from(murmur128(solcInput)).toString('hex');
        artifact = {
          ...hardhatArtifact,
          ...buildInfo.output.contracts[hardhatArtifact.sourceName][
            contractName
          ],
          solcInput,
          solcInputHash,
        };
      } else {
        artifact = {
          ...hardhatArtifact,
        };
      }
    }
    if (artifact) {
      return artifact;
    }
  }
}
Example #5
Source File: hardhat.config.ts    From hardhat-deploy with MIT License 5 votes vote down vote up
task(TASK_COMPILE).setAction(async (args, hre, runSuper) => {
  await runSuper(args);
  const extendedArtifactFolderpath = 'extendedArtifacts';
  fs.emptyDirSync(extendedArtifactFolderpath);
  const artifactPaths = await hre.artifacts.getArtifactPaths();
  for (const artifactPath of artifactPaths) {
    const artifact: Artifact = await fs.readJSON(artifactPath);
    const artifactName = path.basename(artifactPath, '.json');
    const artifactDBGPath = path.join(
      path.dirname(artifactPath),
      artifactName + '.dbg.json'
    );
    const artifactDBG = await fs.readJSON(artifactDBGPath);
    const buildinfoPath = path.join(
      path.dirname(artifactDBGPath),
      artifactDBG.buildInfo
    );
    const buildInfo: BuildInfo = await fs.readJSON(buildinfoPath);
    const output =
      buildInfo.output.contracts[artifact.sourceName][artifactName];

    // TODO decide on ExtendedArtifact vs Artifact vs Deployment type
    // save space by not duplicating bytecodes
    if (output.evm?.bytecode?.object) {
      // eslint-disable-next-line @typescript-eslint/no-explicit-any
      (output.evm.bytecode.object as any) = undefined;
    }
    if (output.evm?.deployedBytecode?.object) {
      // eslint-disable-next-line @typescript-eslint/no-explicit-any
      (output.evm.deployedBytecode.object as any) = undefined;
    }
    // -----------------------------------------

    const solcInput = JSON.stringify(buildInfo.input, null, '  ');
    const solcInputHash = Buffer.from(murmur128(solcInput)).toString('hex');
    const extendedArtifact = {
      ...artifact,
      ...output,
      solcInput,
      solcInputHash,
    };
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    (extendedArtifact._format as any) = undefined;
    fs.writeFileSync(
      path.join(extendedArtifactFolderpath, artifactName + '.json'),
      JSON.stringify(extendedArtifact, null, '  ')
    );
  }
});
Example #6
Source File: DeploymentsManager.ts    From hardhat-deploy with MIT License 4 votes vote down vote up
constructor(env: HardhatRuntimeEnvironment, network: Network) {
    log('constructing DeploymentsManager');

    this.network = network;

    this.impersonateUnknownAccounts = true;
    this.impersonatedAccounts = [];
    this.db = {
      gasUsed: BigNumber.from(0),
      accountsLoaded: false,
      namedAccounts: {},
      unnamedAccounts: [],
      deploymentsLoaded: false,
      deployments: {},
      migrations: {},
      writeDeploymentsToFiles: true, // should default to true ? so we can run scripts that use `deploy` by default
      fixtureCounter: 0,
      snapshotCounter: 0,
      pastFixtures: {},
      logEnabled: process.env['HARDHAT_DEPLOY_LOG'] ? true : false,
      pendingTransactions: {},
      savePendingTx: false,
      gasPrice: undefined,
      runAsNode: false,
    };
    this.env = env;
    this.deploymentsPath = env.config.paths.deployments;

    // TODO
    // this.env.artifacts = new HardhatDeployArtifacts(this.env.artifacts);

    this.partialExtension = {
      readDotFile: async (name: string): Promise<string> =>
        this.readDotFile(name),
      saveDotFile: async (name: string, content: string): Promise<void> =>
        this.saveDotFile(name, content),
      deleteDotFile: async (name: string): Promise<void> =>
        this.deleteDotFile(name),
      save: async (
        name: string,
        deployment: DeploymentSubmission
      ): Promise<void> => {
        this.saveDeployment(name, deployment);
      },
      delete: async (name: string): Promise<void> =>
        this.deleteDeployment(name),
      get: async (name: string) => {
        await this.setup(false);
        const deployment = this.db.deployments[name];
        if (deployment === undefined) {
          throw new Error(`No deployment found for: ${name}`);
        }
        return deployment;
      },
      getOrNull: async (name: string) => {
        await this.setup(false);
        return this.db.deployments[name];
      },
      getDeploymentsFromAddress: async (address: string) => {
        const deployments = [];
        for (const deployment of Object.values(this.db.deployments)) {
          if (deployment.address === address) {
            deployments.push(deployment);
          }
        }
        return deployments;
      },
      all: async () => {
        await this.setup(false);
        return this.db.deployments; // TODO copy
      },
      getArtifact: async (contractName: string): Promise<Artifact> => {
        if (this.db.onlyArtifacts) {
          const artifactFromFolder = await getArtifactFromFolders(
            contractName,
            this.db.onlyArtifacts
          );
          if (!artifactFromFolder) {
            throw new Error(
              `cannot find artifact "${contractName}" from folder ${this.db.onlyArtifacts}`
            );
          }
          return artifactFromFolder as Artifact;
        }
        let artifact: Artifact | ExtendedArtifact | undefined =
          await getArtifactFromFolders(contractName, [
            this.env.config.paths.artifacts,
          ]);
        if (artifact) {
          return artifact as Artifact;
        }
        const importPaths = this.getImportPaths();
        artifact = await getArtifactFromFolders(contractName, importPaths);

        if (!artifact) {
          throw new Error(`cannot find artifact "${contractName}"`);
        }
        return artifact as Artifact;
      },
      getExtendedArtifact: async (
        contractName: string
      ): Promise<ExtendedArtifact> => {
        if (this.db.onlyArtifacts) {
          const artifactFromFolder = await getExtendedArtifactFromFolders(
            contractName,
            this.db.onlyArtifacts
          );
          if (!artifactFromFolder) {
            throw new Error(
              `cannot find artifact "${contractName}" from folder ${this.db.onlyArtifacts}`
            );
          }
          return artifactFromFolder as ExtendedArtifact;
        }
        let artifact: ExtendedArtifact | undefined =
          await getExtendedArtifactFromFolders(contractName, [
            this.env.config.paths.artifacts,
          ]);
        if (artifact) {
          return artifact;
        }
        const importPaths = this.getImportPaths();
        artifact = await getExtendedArtifactFromFolders(
          contractName,
          importPaths
        );
        if (artifact) {
          return artifact;
        }

        if (!artifact) {
          throw new Error(`cannot find artifact "${contractName}"`);
        }
        return artifact;
      },
      run: (
        tags?: string | string[],
        options: {
          resetMemory?: boolean;
          deletePreviousDeployments?: boolean;
          writeDeploymentsToFiles?: boolean;
          export?: string;
          exportAll?: string;
        } = {
          resetMemory: true,
          writeDeploymentsToFiles: false,
          deletePreviousDeployments: false,
        }
      ) => {
        return this.runDeploy(tags, {
          resetMemory:
            options.resetMemory === undefined ? true : options.resetMemory,
          deletePreviousDeployments:
            options.deletePreviousDeployments === undefined
              ? false
              : options.deletePreviousDeployments,
          writeDeploymentsToFiles:
            options.writeDeploymentsToFiles === undefined
              ? false
              : options.writeDeploymentsToFiles,
          export: options.export,
          exportAll: options.exportAll,
          log: false,
          savePendingTx: false,
        });
      },
      fixture: async (
        tags?: string | string[],
        options?: {
          fallbackToGlobal?: boolean;
          keepExistingDeployments?: boolean;
        }
      ) => {
        await this.setup(tags === undefined);
        options = {fallbackToGlobal: true, ...options};
        if (typeof tags === 'string') {
          tags = [tags];
        }
        const globalKey = '::global';
        const globalFixture = this.db.pastFixtures[globalKey];

        let fixtureKey = globalKey;
        if (tags !== undefined) {
          fixtureKey = '::' + tags.join('.');
        }

        if (this.db.pastFixtures[fixtureKey]) {
          const pastFixture = this.db.pastFixtures[fixtureKey];
          const success = await this.revertSnapshot(pastFixture);
          if (success) {
            return this.db.deployments;
          } else {
            delete this.db.pastFixtures[fixtureKey];
          }
        }
        if (globalFixture && options.fallbackToGlobal) {
          const success = await this.revertSnapshot(globalFixture);
          if (success) {
            return this.db.deployments;
          } else {
            delete this.db.pastFixtures[globalKey];
          }
        }
        await this.runDeploy(tags, {
          resetMemory: !options.keepExistingDeployments,
          writeDeploymentsToFiles: false,
          deletePreviousDeployments: false,
          log: false,
          savePendingTx: false,
        });

        await this.saveSnapshot(fixtureKey);
        return this.db.deployments;
      },
      createFixture: <T, O>(func: FixtureFunc<T, O>) => {
        const baseId = '' + ++this.db.fixtureCounter + '::';
        return async (options?: O) => {
          let id = baseId;
          if (options !== undefined) {
            id = id + JSON.stringify(options);
          }
          const saved = this.db.pastFixtures[id];
          if (saved) {
            const success = await this.revertSnapshot(saved);
            if (success) {
              return saved.data;
            }
          }
          const data = await func(this.env, options);
          await this.saveSnapshot(id, data);
          return data;
        };
      },
      log: (...args: any[]) => {
        if (this.db.logEnabled) {
          console.log(...args);
        }
      },
      getNetworkName: () => this.getNetworkName(),
      getGasUsed: () => this.db.gasUsed.toNumber(),
    } as PartialExtension;

    const print = (msg: string) => {
      if (this.db.logEnabled) {
        process.stdout.write(msg);
      }
    };

    log('adding helpers');
    const helpers = addHelpers(
      this,
      this.partialExtension,
      this.network,
      this.partialExtension.getArtifact,
      async (
        name: string,
        deployment: DeploymentSubmission,
        artifactName?: string
      ): Promise<void> => {
        if (
          artifactName &&
          this.db.writeDeploymentsToFiles &&
          this.network.saveDeployments
        ) {
          // toSave (see deployments.save function)
          const extendedArtifact =
            await this.partialExtension.getExtendedArtifact(artifactName);
          deployment = {
            ...deployment,
            ...extendedArtifact,
          };
        }
        await this.partialExtension.save(name, deployment);
      },
      () => {
        return this.db.writeDeploymentsToFiles && this.network.saveDeployments;
      },
      this.onPendingTx.bind(this),
      async () => {
        // TODO extraGasPrice ?
        let gasPrice: BigNumber | undefined;
        let maxFeePerGas: BigNumber | undefined;
        let maxPriorityFeePerGas: BigNumber | undefined;
        if (this.db.gasPrice) {
          gasPrice = BigNumber.from(this.db.gasPrice);
        } else {
          if (this.db.maxFeePerGas) {
            maxFeePerGas = BigNumber.from(this.db.maxFeePerGas);
          }
          if (this.db.maxPriorityFeePerGas) {
            maxPriorityFeePerGas = BigNumber.from(this.db.maxPriorityFeePerGas);
          }
        }
        return {gasPrice, maxFeePerGas, maxPriorityFeePerGas};
      },
      this.partialExtension.log,
      print
    );

    this.deploymentsExtension = helpers.extension;
    this.utils = helpers.utils;
  }
Example #7
Source File: index.ts    From hardhat-deploy with MIT License 4 votes vote down vote up
task('export-artifacts')
  .addPositionalParam(
    'dest',
    'destination folder where the extended artifacts files will be written to',
    undefined,
    types.string
  )
  .addFlag(
    'solcInput',
    'if set, artifacts will have an associated solcInput files (required for old version of solidity to ensure verifiability'
  )
  .addFlag(
    'includingEmptyBytecode',
    'if set, even contract without bytecode (like interfaces) will be exported'
  )
  .addFlag(
    'includingNoPublicFunctions',
    'if set, even contract without public interface (like imternal libraries) will be exported'
  )
  .addOptionalParam(
    'exclude',
    'list of contract names separated by commas to exclude',
    undefined,
    types.string
  )
  .addOptionalParam(
    'include',
    'list of contract names separated by commas to include. If specified, only these will be considered',
    undefined,
    types.string
  )
  .addFlag(
    'hideSources',
    'if set, the artifacts files will not contain source code (metadata or other data exposing it) unless specified via --sources-for'
  )
  .addOptionalParam(
    'sourcesFor',
    'list of contract names separated by commas to include source (metadata,etc...) for (see --hide-sources)',
    undefined,
    types.string
  )
  .setAction(async (args, hre) => {
    await hre.run('compile');
    const argsInclude: string[] = args.include ? args.include.split(',') : [];
    const checkInclude = argsInclude.length > 0;
    const include = argsInclude.reduce(
      (result: Record<string, boolean>, item: string) => {
        result[item] = true;
        return result;
      },
      {}
    );
    const argsExclude: string[] = args.exclude ? args.exclude.split(',') : [];
    const exclude = argsExclude.reduce(
      (result: Record<string, boolean>, item: string) => {
        result[item] = true;
        return result;
      },
      {}
    );
    const argsSourcesFor: string[] = args.sourcesFor
      ? args.sourcesFor.split(',')
      : [];
    const sourcesFor = argsSourcesFor.reduce(
      (result: Record<string, boolean>, item: string) => {
        result[item] = true;
        return result;
      },
      {}
    );
    const extendedArtifactFolderpath = args.dest;
    fs.emptyDirSync(extendedArtifactFolderpath);
    const artifactPaths = await hre.artifacts.getArtifactPaths();
    for (const artifactPath of artifactPaths) {
      const artifact: Artifact = await fs.readJSON(artifactPath);
      const artifactName = path.basename(artifactPath, '.json');
      if (exclude[artifactName]) {
        continue;
      }
      if (checkInclude && !include[artifactName]) {
        continue;
      }
      const artifactDBGPath = path.join(
        path.dirname(artifactPath),
        artifactName + '.dbg.json'
      );
      const artifactDBG = await fs.readJSON(artifactDBGPath);
      const buildinfoPath = path.join(
        path.dirname(artifactDBGPath),
        artifactDBG.buildInfo
      );
      const buildInfo: BuildInfo = await fs.readJSON(buildinfoPath);
      const output =
        buildInfo.output.contracts[artifact.sourceName][artifactName];

      if (!args.includingNoPublicFunctions) {
        if (
          !artifact.abi ||
          artifact.abi.filter((v) => v.type !== 'event').length === 0
        ) {
          continue;
        }
      }

      if (!args.includingEmptyBytecode) {
        if (!artifact.bytecode || artifact.bytecode === '0x') {
          continue;
        }
      }

      // TODO decide on ExtendedArtifact vs Artifact vs Deployment type
      // save space by not duplicating bytecodes
      if (output.evm?.bytecode?.object) {
        // eslint-disable-next-line @typescript-eslint/no-explicit-any
        (output.evm.bytecode.object as any) = undefined;
      }
      if (output.evm?.deployedBytecode?.object) {
        // eslint-disable-next-line @typescript-eslint/no-explicit-any
        (output.evm.deployedBytecode.object as any) = undefined;
      }
      // -----------------------------------------

      const extendedArtifact: ExtendedArtifact = {
        ...artifact,
        ...output,
      };
      // eslint-disable-next-line @typescript-eslint/no-explicit-any
      (extendedArtifact as any)._format = undefined;

      if (args.solcInput) {
        const solcInput = JSON.stringify(buildInfo.input, null, '  ');
        const solcInputHash = Buffer.from(murmur128(solcInput)).toString('hex');
        extendedArtifact.solcInput = solcInput;
        extendedArtifact.solcInputHash = solcInputHash;
      }

      // eslint-disable-next-line @typescript-eslint/no-explicit-any
      let dataToWrite: any = extendedArtifact;
      if (args.hideSources && !sourcesFor[artifactName]) {
        dataToWrite = {
          // eslint-disable-next-line @typescript-eslint/no-explicit-any
          contractName: (extendedArtifact as any).contractName,
          // eslint-disable-next-line @typescript-eslint/no-explicit-any
          sourceName: (extendedArtifact as any).sourceName,
          abi: extendedArtifact.abi,
          bytecode: extendedArtifact.bytecode,
          deployedBytecode: extendedArtifact.deployedBytecode,
          linkReferences: extendedArtifact.linkReferences,
          deployedLinkReferences: extendedArtifact.deployedLinkReferences,
          devdoc: extendedArtifact.devdoc,
          userdoc: extendedArtifact.userdoc,
          evm: extendedArtifact.evm
            ? {
                gasEstimates: extendedArtifact.evm.gasEstimates,
                methodIdentifiers: extendedArtifact.evm.methodIdentifiers,
              }
            : undefined,
        };
      }

      let filepath = path.join(
        extendedArtifactFolderpath,
        artifactName + '.json'
      );
      if (dataToWrite.sourceName) {
        if (dataToWrite.contractName) {
          filepath = path.join(
            extendedArtifactFolderpath,
            dataToWrite.sourceName,
            dataToWrite.contractName + '.json'
          );
        } else {
          filepath = path.join(
            extendedArtifactFolderpath,
            dataToWrite.sourceName,
            artifactName + '.json'
          );
        }
      }

      fs.ensureFileSync(filepath);
      fs.writeFileSync(filepath, JSON.stringify(dataToWrite, null, '  '));
    }
  });