or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

chai-matchers.mdcompiler-utilities.mdcontract-deployment.mdens-utilities.mdindex.mdmock-contracts.mdoptimism-provider.mdprovider-testing.md
tile.json

compiler-utilities.mddocs/

Compiler Utilities

Comprehensive Solidity compilation system including library linking, project compilation, TypeChain integration, and advanced configuration management for smart contract development workflows.

Capabilities

Project Compilation

High-level functions for compiling entire Solidity projects with automatic configuration detection and compilation pipeline management.

/**
 * Compile entire project using waffle configuration
 * @param configPath - Optional path to waffle config file
 * @returns Promise that resolves when compilation completes
 */
function compileProject(configPath?: string): Promise<void>;

/**
 * Compile contracts and save artifacts to output directory
 * @param input - Compilation configuration options
 * @returns Promise that resolves when compilation and save complete
 */
function compileAndSave(input: InputConfig): Promise<void>;

/**
 * Compile contracts and return compilation results
 * @param input - Compilation configuration options
 * @returns Promise resolving to compilation output
 */
function compile(input: InputConfig): Promise<any>;

Usage Examples:

import { compileProject, compileAndSave, compile } from "@ethereum-waffle/compiler";

// Compile project with default config
await compileProject();

// Compile with custom config file
await compileProject("./waffle-config.json");

// Compile and save with custom options
await compileAndSave({
  sourceDirectory: "./contracts",
  outputDirectory: "./build",
  compilerType: "solcjs",
  compilerVersion: "0.8.19"
});

// Compile and get results without saving
const compilationResults = await compile({
  sourceDirectory: "./contracts",
  compilerType: "native"
});

console.log("Compiled contracts:", compilationResults.contracts);

Configuration Management

Comprehensive configuration system supporting multiple compiler types, output formats, and TypeChain integration.

/**
 * Complete configuration interface for Waffle compilation
 */
interface Config {
  /** Directory containing Solidity source files */
  sourceDirectory: string;
  /** Directory to output compiled artifacts */
  outputDirectory: string;
  /** Directory to output flattened contracts */
  flattenOutputDirectory: string;
  /** Directory containing node_modules for import resolution */
  nodeModulesDirectory: string;
  /** Directory for compilation cache */
  cacheDirectory: string;
  /** Type of Solidity compiler to use */
  compilerType: 'native' | 'dockerized-solc' | 'solcjs' | 'dockerized-vyper';
  /** Specific compiler version to use */
  compilerVersion: string;
  /** Additional paths allowed for imports */
  compilerAllowedPaths: string[];
  /** Raw compiler options passed to solc */
  compilerOptions: any;
  /** Generate human-readable ABI files */
  outputHumanReadableAbi: boolean;
  /** Format of compilation output */
  outputType: 'multiple' | 'combined' | 'all' | 'minimal';
  /** Enable TypeChain type generation */
  typechainEnabled: boolean;
  /** Output directory for TypeChain types */
  typechainOutputDir: string;
}

/**
 * Partial configuration for input - all fields optional
 */
type InputConfig = Partial<Config>;

/**
 * Convert input configuration to complete configuration with defaults
 * @param input - Partial configuration options
 * @returns Complete configuration with defaults applied
 */
function inputToConfig(input: InputConfig): Config;

Usage Examples:

import { inputToConfig, Config } from "@ethereum-waffle/compiler";

// Create config with defaults
const config = inputToConfig({
  sourceDirectory: "./src/contracts",
  compilerType: "solcjs",
  typechainEnabled: true
});

// Full configuration example
const fullConfig: Config = {
  sourceDirectory: "./contracts",
  outputDirectory: "./artifacts",
  flattenOutputDirectory: "./flattened",
  nodeModulesDirectory: "./node_modules",
  cacheDirectory: "./cache",
  compilerType: "native",
  compilerVersion: "0.8.19",
  compilerAllowedPaths: ["./lib", "./interfaces"],
  compilerOptions: {
    optimizer: {
      enabled: true,
      runs: 200
    }
  },
  outputHumanReadableAbi: true,
  outputType: "multiple",
  typechainEnabled: true,
  typechainOutputDir: "./typechain"
};

// Use configuration for compilation
await compileAndSave(fullConfig);

TypeChain Integration

Automatic TypeScript type generation for compiled contracts enabling full type safety in contract interactions.

/**
 * Generate TypeScript types for compiled contracts
 * @param config - Configuration containing TypeChain settings
 * @returns Promise that resolves when type generation completes
 */
function generateTypes(config: Config): Promise<void>;

Usage Examples:

import { generateTypes, inputToConfig } from "@ethereum-waffle/compiler";

// Generate types after compilation
const config = inputToConfig({
  sourceDirectory: "./contracts",
  outputDirectory: "./artifacts",
  typechainEnabled: true,
  typechainOutputDir: "./typechain"
});

await compileAndSave(config);
await generateTypes(config);

// Use generated types in testing
import { MyContract__factory } from "./typechain";

const contractFactory = new MyContract__factory(wallet);
const contract = await contractFactory.deploy(constructorArg);

// contract is now fully typed with all methods and events
await contract.myMethod(typedParameter);

Capabilities

Library Linking

Function for linking deployed library addresses to contract bytecode, enabling contracts to use external library functions during deployment.

/**
 * Link library addresses to contract bytecode placeholders
 * @param contract - Contract with linkable bytecode
 * @param libraryName - Name of the library to link
 * @param libraryAddress - Deployed address of the library
 */
function link(
  contract: LinkableContract, 
  libraryName: string, 
  libraryAddress: string
): void;

/**
 * Interface for contracts that support library linking
 */
interface LinkableContract {
  evm: {
    bytecode: {
      object: any;
    };
  };
}

Usage Examples:

import { link, deployContract } from "ethereum-waffle";

// Deploy library contract first
const mathLibrary = await deployContract(wallet, MathLibraryJson);

// Load main contract JSON
const mainContractJson = require("./artifacts/MainContract.json");

// Link library to main contract
link(mainContractJson, "MathLibrary", mathLibrary.address);

// Deploy linked contract
const mainContract = await deployContract(wallet, mainContractJson, [constructorArgs]);

// Contract can now use library functions
await mainContract.useLibraryFunction(42);

Advanced Linking Scenarios

Complex library linking patterns for contracts with multiple library dependencies and nested library relationships.

Multiple Library Linking:

import { link, deployContract } from "ethereum-waffle";

// Deploy multiple libraries
const stringLibrary = await deployContract(wallet, StringLibraryJson);
const mathLibrary = await deployContract(wallet, MathLibraryJson);
const utilsLibrary = await deployContract(wallet, UtilsLibraryJson);

// Load contract that uses multiple libraries
const complexContractJson = require("./artifacts/ComplexContract.json");

// Link all required libraries
link(complexContractJson, "StringLibrary", stringLibrary.address);
link(complexContractJson, "MathLibrary", mathLibrary.address);
link(complexContractJson, "UtilsLibrary", utilsLibrary.address);

// Deploy contract with all libraries linked
const complexContract = await deployContract(wallet, complexContractJson);

Nested Library Dependencies:

import { link, deployContract } from "ethereum-waffle";

// Deploy base library first
const baseLibrary = await deployContract(wallet, BaseLibraryJson);

// Load dependent library and link base library
const dependentLibraryJson = require("./artifacts/DependentLibrary.json");
link(dependentLibraryJson, "BaseLibrary", baseLibrary.address);

// Deploy dependent library
const dependentLibrary = await deployContract(wallet, dependentLibraryJson);

// Load main contract and link both libraries
const mainContractJson = require("./artifacts/MainContract.json");
link(mainContractJson, "BaseLibrary", baseLibrary.address);
link(mainContractJson, "DependentLibrary", dependentLibrary.address);

// Deploy main contract
const mainContract = await deployContract(wallet, mainContractJson);

Library Linking with TypeChain:

import { link } from "ethereum-waffle";
import { MyContract__factory, MyLibrary__factory } from "./typechain";

// Deploy library using TypeChain factory
const libraryFactory = new MyLibrary__factory(wallet);
const library = await libraryFactory.deploy();

// Get contract JSON for linking (if needed for complex scenarios)
const contractJson = require("./artifacts/contracts/MyContract.sol/MyContract.json");
link(contractJson, "MyLibrary", library.address);

// Deploy main contract with linked library
const mainContract = await deployContract(wallet, contractJson);

Library Linking Process

The linking process modifies contract bytecode by replacing library placeholders with actual deployed addresses:

  1. Placeholder Identification: Finds library name placeholders in bytecode
  2. Address Replacement: Replaces placeholders with actual library addresses
  3. Bytecode Modification: Updates the contract's bytecode object in place
  4. Validation: Ensures library address format is correct

Understanding Bytecode Placeholders:

// Before linking - bytecode contains placeholders
const contractJson = require("./artifacts/Contract.json");
console.log(contractJson.evm.bytecode.object);
// Output: "608060405234801561001057600080fd5b50__MathLibrary_________________..."
//                                   ^^^^^^^^^^^^^^^^^^^^^^^^^
//                                   Library placeholder

// After linking
link(contractJson, "MathLibrary", "0x1234567890123456789012345678901234567890");
console.log(contractJson.evm.bytecode.object);
// Output: "608060405234801561001057600080fd5b501234567890123456789012345678901234567890..."
//                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
//                                   Actual library address

Error Handling:

import { link, deployContract } from "ethereum-waffle";

try {
  const contractJson = require("./artifacts/Contract.json");
  
  // This will fail if library name doesn't match placeholder
  link(contractJson, "WrongLibraryName", libraryAddress);
  
} catch (error) {
  console.log("Library linking failed:", error.message);
  // Handle linking error appropriately
}

// Verify contract has required libraries before deployment
function hasUnlinkedLibraries(contractJson: LinkableContract): boolean {
  const bytecode = contractJson.evm.bytecode.object;
  return typeof bytecode === 'string' && bytecode.includes('__') && bytecode.includes('_');
}

if (hasUnlinkedLibraries(contractJson)) {
  throw new Error("Contract has unlinked libraries");
}

Integration with Deployment Workflow

Common patterns for integrating library linking into contract deployment workflows:

import { link, deployContract, MockProvider } from "ethereum-waffle";

async function deployContractWithLibraries(
  wallet: Wallet,
  contractJson: any,
  libraries: Record<string, string>,
  constructorArgs: any[] = []
) {
  // Clone contract JSON to avoid modifying original
  const linkedContract = JSON.parse(JSON.stringify(contractJson));
  
  // Link all required libraries
  for (const [libraryName, libraryAddress] of Object.entries(libraries)) {
    link(linkedContract, libraryName, libraryAddress);
  }
  
  // Deploy with linked libraries
  return deployContract(wallet, linkedContract, constructorArgs);
}

// Usage example
const provider = new MockProvider();
const [wallet] = provider.getWallets();

// Deploy libraries
const mathLib = await deployContract(wallet, MathLibraryJson);
const stringLib = await deployContract(wallet, StringLibraryJson);

// Deploy main contract with libraries
const mainContract = await deployContractWithLibraries(
  wallet,
  MainContractJson,
  {
    "MathLibrary": mathLib.address,
    "StringLibrary": stringLib.address
  },
  [constructorArg1, constructorArg2]
);