trufflesuite/truffle

View on GitHub
packages/resolver/lib/sources/truffle/index.ts

Summary

Maintainability
B
6 hrs
Test Coverage
import path from "path";
import fse from "fs-extra";
import { Deployed } from "./Deployed";
import findContracts from "@truffle/contract-sources";
import type { ResolverSource } from "../../source";
const contract = require("@truffle/contract");
export class Truffle implements ResolverSource {
  options: any;

  constructor(options: any) {
    this.options = options;
  }

  async resolve(importPath: string) {
    if (importPath === `truffle${path.sep}DeployedAddresses.sol`) {
      const sourceFiles = await findContracts(this.options.contracts_directory);

      const buildDirFiles: string[] = fse.existsSync(
        this.options.contracts_build_directory
      )
        ? fse.readdirSync(this.options.contracts_build_directory)
        : [];
      const abstractionFiles = buildDirFiles.filter(file =>
        file.match(/^.*.json$/)
      );

      const mapping: { [key: string]: string | false } = {};

      const blacklist = new Set(["Assert", "DeployedAddresses"]);

      // Ensure we have a mapping for source files and abstraction files
      // to prevent any compile errors in tests.
      sourceFiles.forEach((file: string) => {
        // we need to account for .json and .abi.json files
        const name = path.basename(
          path.basename(path.basename(file, ".sol"), ".json"),
          ".abi"
        );
        if (blacklist.has(name)) return;
        mapping[name] = false;
      });

      abstractionFiles.forEach(file => {
        const name = path.basename(file, ".json");
        if (blacklist.has(name)) return;
        mapping[name] = false;
      });

      const filesData = abstractionFiles.map(file => {
        return fse.readFileSync(
          path.join(this.options.contracts_build_directory, file),
          "utf8"
        );
      });

      const addresses = filesData.map(data => {
        const c = contract(JSON.parse(data));
        c.setNetwork(this.options.network_id);
        if (c.isDeployed()) return c.address;
        return null;
      });

      addresses.forEach((address, i) => {
        const name = path.basename(abstractionFiles[i], ".json");

        if (blacklist.has(name)) return;

        mapping[name] = address;
      });

      const addressSource = Deployed.makeSolidityDeployedAddressesLibrary(
        mapping,
        this.options.compilers
      );
      return { body: addressSource, filePath: importPath };
    }

    // Match both Camel and Pascal casing for console.sol
    if (
      importPath === `truffle${path.sep}Console.sol` ||
      importPath === `truffle${path.sep}console.sol`
    ) {
      // calculating this in webpack env breaks
      let unbundledGanacheConsoleSol;
      // @ts-ignore
      if (typeof BUNDLE_VERSION === "undefined") {
        unbundledGanacheConsoleSol = path.resolve(
          require.resolve("@ganache/console.log/console.sol")
        );
      }
      const actualImportPath =
        // @ts-ignore
        typeof BUNDLE_VERSION !== "undefined"
          ? path.resolve(path.join(__dirname, `console.sol`))
          : unbundledGanacheConsoleSol;
      const body = fse.readFileSync(actualImportPath, { encoding: "utf8" });
      return {
        body,
        filePath: importPath
      };
    }

    const truffleLibraries = [
      "Assert",
      "AssertAddress",
      "AssertAddressArray",
      "AssertBalance",
      "AssertBool",
      "AssertBytes32",
      "AssertBytes32Array",
      "AssertGeneral",
      "AssertInt",
      "AssertIntArray",
      "AssertString",
      "AssertUint",
      "AssertUintArray",
      "SafeSend"
    ];

    for (const lib of truffleLibraries) {
      if (importPath === `truffle${path.sep}${lib}.sol`) {
        const actualImportPath =
          // @ts-ignore
          typeof BUNDLE_VERSION !== "undefined"
            ? path.resolve(path.join(__dirname, `${lib}.sol`))
            : path.resolve(__dirname, "../../../..", "solidity", `${lib}.sol`);
        const body = fse.readFileSync(actualImportPath, { encoding: "utf8" });
        return { body, filePath: importPath };
      }
    }

    return { body: undefined, filePath: undefined };
  }

  require(): null {
    // return null to let another source handle this behavior
    // (will be covered by FS source)
    return null;
  }

  resolveDependencyPath(_importPath: string, dependencyPath: string) {
    return dependencyPath;
  }
}