JavaScript bindings for the Solidity compiler with Standard JSON I/O interface
—
Integration with external SMT solvers for formal verification through Solidity's SMTChecker with support for Z3, Eldarica, and cvc5.
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 })
);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');
}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
z3-smt2 rlimit=20000000 rewriter.pull_cheap_ite=true fp.spacer.q3.use_qgen=true fp.spacer.mbqi=false fp.spacer.ground_pobs=falseEldarica: Horn clause solver
eld-horn -t:10 (10 second timeout)cvc5: SMT solver from Stanford
cvc5--lang=smt2 --tlimit=10000Usage 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);
}
}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"]
}
}
};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
}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