trufflesuite/truffle

View on GitHub
packages/dashboard-hardhat-plugin/src/index.ts

Summary

Maintainability
A
1 hr
Test Coverage
import { name as pluginName } from "../package.json";
import { URL } from "url";
import util from "util";
import { extendConfig, task } from "hardhat/config";
import { HardhatPluginError } from "hardhat/plugins";
import type {
  HardhatConfig,
  HardhatUserConfig,
  HttpNetworkConfig,
  TruffleDashboardNetworkConfigurableKeys
} from "hardhat/types";

import { DashboardMessageBusClient } from "@truffle/dashboard-message-bus-client";
import * as FromHardhat from "@truffle/from-hardhat";
import TruffleConfig from "@truffle/config";

import "./type-extensions";

const defaults = {
  networkName: "truffleDashboard",
  host: "localhost",
  port: 24012,
  gas: "auto",
  gasPrice: "auto",
  gasMultiplier: 1,
  timeout: 0,
  httpHeaders: {}
} as const;

extendConfig((config: HardhatConfig, userConfig: HardhatUserConfig) => {
  // Validate configuration and fill in defaults for missing user config fields
  const {
    dashboardNetworkName,
    dashboardNetworkConfig: dashboardNetworkUserConfig
  } = getTruffleDashboardUserConfig(config, userConfig);

  // Look for custom Truffle Dashboard configuration inside truffle-config.js
  // (if it exists)
  const { host, port } = detectDashboardSettings();

  // Generate URL and supply other plugin invariants
  // (e.g., accounts should always be "remote" for Truffle Dashboard)
  const dashboardNetworkConfig: HttpNetworkConfig = {
    url: `http://${host}:${port}/rpc`,
    accounts: "remote",
    ...dashboardNetworkUserConfig
  };

  // Capture completed configuration
  config.truffle = {
    dashboardNetworkName,
    dashboardNetworkConfig
  };

  // Add managed network
  config.networks[dashboardNetworkName] = dashboardNetworkConfig;
});

task("compile", "Compile with Truffle Dashboard support").setAction(
  async (taskArgs, env, runSuper) => {
    // Run Hardhat compilation
    const result = await runSuper();

    try {
      await FromHardhat.expectHardhat();

      // Extract Truffle Dashboard host and port from complete Hardhat config
      const { hostname: host, port } = new URL(
        env.config.truffle.dashboardNetworkConfig.url
      );

      console.log("Preparing Truffle compilation");

      // Prepare Truffle compilations
      let compilations = await FromHardhat.prepareCompilations();

      // Create Message Bus client
      let messageBusClient = new DashboardMessageBusClient({
        host,
        port: parseInt(port)
      });

      console.log("Sending Truffle compilation to dashboard");

      // Send Truffle compilations to dashboard
      const publishLifecycle = await messageBusClient.publish({
        type: "cli-event",
        payload: {
          label: "workflow-compile-result",
          data: { compilations }
        }
      });
      publishLifecycle.abandon();

      console.log("Compilation successfully sent!");
    } catch (hardhatError) {
      console.warn(
        "The Truffle Dashboard plugin failed to compile: ",
        hardhatError
      );
    }

    return result;
  }
);

function detectDashboardSettings() {
  let truffleConfig;
  try {
    truffleConfig = TruffleConfig.detect();
  } catch {
    truffleConfig = {
      dashboard: {}
    };
  }

  const { host = defaults.host, port = defaults.port } =
    truffleConfig.dashboard;

  return {
    host,
    port
  };
}

function getTruffleDashboardUserConfig(
  config: HardhatConfig,
  userConfig: HardhatUserConfig
) {
  const {
    dashboardNetworkName = defaults.networkName,
    dashboardNetworkConfig: dashboardNetworkUserConfig = {}
  } = userConfig.truffle || {};

  const {
    gas = defaults.gas,
    gasPrice = defaults.gasPrice,
    gasMultiplier = defaults.gasMultiplier,
    timeout = defaults.timeout,
    httpHeaders = defaults.httpHeaders
  } = dashboardNetworkUserConfig;

  const dashboardNetworkConfig: Pick<
    HttpNetworkConfig,
    TruffleDashboardNetworkConfigurableKeys
  > = {
    gas,
    gasPrice,
    gasMultiplier,
    timeout,
    httpHeaders
  };

  const networkIsDefinedExplicitly =
    userConfig.networks && dashboardNetworkName in userConfig.networks;

  if (networkIsDefinedExplicitly) {
    throw new HardhatPluginError(
      pluginName,
      `Manual network config disallowed.\n\n` +
        `This plugin manages your Truffle Dashboard network config for you,\n` +
        `but your Hardhat config also contains \`config.networks["${dashboardNetworkName}"]\`.\n\n` +
        `You can fix this error by removing \`config.networks["${dashboardNetworkName}"]\`.\n\n`  +
        `Please see the README for more details about how to configure this plugin:\n` +
        `  https://www.npmjs.com/package/@truffle/dashboard-hardhat-plugin`
    );
  }

  return {
    dashboardNetworkName,
    dashboardNetworkConfig
  };
}