CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-solc

JavaScript bindings for the Solidity compiler with Standard JSON I/O interface

Pending
Overview
Eval results
Files

smt-integration.mddocs/

SMT Integration

Integration with external SMT solvers for formal verification through Solidity's SMTChecker with support for Z3, Eldarica, and cvc5.

Capabilities

SMT Callback Creation

Create callback functions for SMT solver integration during compilation.

/**
 * Create SMT solver callback for compilation
 * @param solverFunction - Function that takes SMT queries and returns solutions
 * @param solver - Optional solver configuration object
 * @returns Callback function compatible with compile() method
 */
function smtCallback(
  solverFunction: (query: string, solver?: any) => string,
  solver?: any
): (query: string) => { contents: string } | { error: string };

Usage Examples:

import solc from "solc";
import smtchecker from "solc/smtchecker";
import smtsolver from "solc/smtsolver";

const input = {
  language: 'Solidity',
  sources: {
    'test.sol': {
      content: 'contract C { function f(uint x) public { assert(x > 0); } }'
    }
  },
  settings: {
    modelChecker: {
      engine: "chc",
      solvers: ["smtlib2"]
    }
  }
};

// Create SMT callback
const callback = smtchecker.smtCallback(
  smtsolver.smtSolver,
  smtsolver.availableSolvers[0]
);

// Compile with SMT verification
const output = JSON.parse(
  solc.compile(JSON.stringify(input), { smtSolver: callback })
);

SMT Query Handling

Process SMT queries from compiler output and provide solutions for re-compilation.

/**
 * Handle SMT queries from compiler output
 * @param inputJSON - Original Standard JSON input object
 * @param outputJSON - Standard JSON output containing SMT queries
 * @param solverFunction - Function to solve individual SMT queries
 * @param solver - Optional solver configuration
 * @returns Modified input JSON with SMT responses, or null if no queries
 */
function handleSMTQueries(
  inputJSON: any,
  outputJSON: any,
  solverFunction: (query: string, solver?: any) => string,
  solver?: any
): any | null;

Usage Examples:

import smtchecker from "solc/smtchecker";
import smtsolver from "solc/smtsolver";

// First compilation to get SMT queries
const input = { /* standard JSON input with modelChecker settings */ };
const firstOutput = JSON.parse(solc.compile(JSON.stringify(input)));

// Process SMT queries if present
const modifiedInput = smtchecker.handleSMTQueries(
  input,
  firstOutput,
  smtsolver.smtSolver,
  smtsolver.availableSolvers[0]
);

if (modifiedInput) {
  // Re-compile with SMT solutions
  const finalOutput = JSON.parse(solc.compile(JSON.stringify(modifiedInput)));
  console.log('SMT verification results:', finalOutput.errors);
} else {
  console.log('No SMT queries to process');
}

SMT Solver Management

Direct SMT solver integration with support for multiple solver backends.

/**
 * Solve an individual SMT query using available solvers
 * @param query - SMT-LIB2 formatted query string
 * @param solver - Optional solver configuration (uses first available if not specified)
 * @returns Solver output string (sat/unsat/unknown with optional model)
 */
function smtSolver(query: string, solver?: SolverConfig): string;

interface SolverConfig {
  name: string;
  command: string;
  params: string;
}

/** Array of locally available SMT solvers detected at runtime */
const availableSolvers: SolverConfig[];

Available Solvers:

The package supports three SMT solvers if they are installed locally:

  • Z3: Microsoft Research SMT solver

    • Command: z3
    • Default parameters: -smt2 rlimit=20000000 rewriter.pull_cheap_ite=true fp.spacer.q3.use_qgen=true fp.spacer.mbqi=false fp.spacer.ground_pobs=false
  • Eldarica: Horn clause solver

    • Command: eld
    • Default parameters: -horn -t:10 (10 second timeout)
  • cvc5: SMT solver from Stanford

    • Command: cvc5
    • Default parameters: --lang=smt2 --tlimit=10000

Usage Examples:

import smtsolver from "solc/smtsolver";

// Check available solvers
console.log('Available solvers:', smtsolver.availableSolvers);

if (smtsolver.availableSolvers.length === 0) {
  console.log('No SMT solvers found. Install Z3, Eldarica, or cvc5.');
} else {
  // Use first available solver
  const query = `(set-logic QF_LIA)
(declare-fun x () Int)
(assert (> x 0))
(check-sat)
(get-model)`;

  try {
    const result = smtsolver.smtSolver(query);
    console.log('Solver result:', result); // "sat" or "unsat" etc.
  } catch (error) {
    console.error('Solver error:', error.message);
  }
}

Model Checker Configuration

Configure the Solidity model checker for different verification approaches.

interface ModelCheckerSettings {
  /** Verification engine to use */
  engine: "chc" | "bmc";
  /** SMT solvers to use (defaults to ["smtlib2"]) */
  solvers?: string[];
  /** Timeout in milliseconds */
  timeout?: number;
  /** Verification targets */
  targets?: ("assert" | "underflow" | "overflow" | "divByZero" | "constantCondition" | "popEmptyArray" | "outOfBounds")[];
}

Usage Examples:

// Basic assertion checking
const basicConfig = {
  language: 'Solidity',
  sources: { /* ... */ },
  settings: {
    modelChecker: {
      engine: "chc",
      solvers: ["smtlib2"]
    }
  }
};

// Advanced configuration
const advancedConfig = {
  language: 'Solidity',
  sources: { /* ... */ },
  settings: {
    modelChecker: {
      engine: "bmc",
      solvers: ["smtlib2"],
      timeout: 30000,
      targets: ["assert", "overflow", "underflow"]
    }
  }
};

Error Handling and Timeouts

SMT solvers may timeout or encounter errors. The integration handles these cases gracefully:

import smtsolver from "solc/smtsolver";

try {
  const result = smtsolver.smtSolver(complexQuery);
  
  if (result.startsWith('sat')) {
    console.log('Query is satisfiable');
  } else if (result.startsWith('unsat')) {
    console.log('Query is unsatisfiable');
  } else if (result.startsWith('unknown')) {
    console.log('Solver could not determine satisfiability');
  }
} catch (error) {
  console.error('SMT solver failed:', error.message);
  // Continue without SMT verification
}

Verification Workflow

Complete workflow for SMT-based formal verification:

import solc from "solc";
import smtchecker from "solc/smtchecker";
import smtsolver from "solc/smtsolver";

async function verifyContract(sourceCode: string) {
  const input = {
    language: 'Solidity',
    sources: {
      'contract.sol': { content: sourceCode }
    },
    settings: {
      modelChecker: {
        engine: "chc",
        solvers: ["smtlib2"]
      },
      outputSelection: {
        '*': { '*': ['*'] }
      }
    }
  };

  try {
    // First compilation
    const output = JSON.parse(solc.compile(JSON.stringify(input)));
    
    if (smtsolver.availableSolvers.length === 0) {
      console.log('No SMT solvers available - skipping verification');
      return output;
    }

    // Handle SMT queries
    const modifiedInput = smtchecker.handleSMTQueries(
      input,
      output,
      smtsolver.smtSolver,
      smtsolver.availableSolvers[0]
    );

    if (modifiedInput) {
      console.log('Re-running compilation with SMT solutions...');
      const finalOutput = JSON.parse(solc.compile(JSON.stringify(modifiedInput)));
      return finalOutput;
    }

    return output;
    
  } catch (error) {
    console.error('Verification failed:', error);
    throw error;
  }
}

// Usage
const contractCode = `
contract SafeMath {
  function add(uint a, uint b) public pure returns (uint) {
    uint c = a + b;
    assert(c >= a); // This assertion will be verified
    return c;
  }
}`;

verifyContract(contractCode).then(result => {
  const errors = result.errors || [];
  const warnings = errors.filter(e => e.severity === 'warning');
  const errorMessages = errors.filter(e => e.severity === 'error');
  
  console.log(`Verification complete: ${errorMessages.length} errors, ${warnings.length} warnings`);
});

Install with Tessl CLI

npx tessl i tessl/npm-solc

docs

abi-utilities.md

cli.md

compilation.md

index.md

linking.md

smt-integration.md

utilities.md

version-management.md

tile.json