solc-js

repository·master·Indexed 23 days ago

https://github.com/argotorg/solc-js

JavaScript bindings for the Solidity compiler, enabling smart contract compilation within Node.js, browser, or Electron environments using Emscripten-compiled binaries. It provides a high-level API via solc.compile(), a low-level API for specific compiler interfaces, and utilities for linking bytecode, updating ABIs, and loading remote compiler versions.

Tokens
2.8K
Snippets
8
Records
15
Agent score
31%

What's inside solc-js

  1. Use solc in a web browser via Web Workers

    master

    Compilation is a resource-intensive task that can block the browser's main thread. Because some browsers disallow synchronous compilation on the main thread for modules larger than 4KB, the only supported way to use solc in a web browser is through a Web Worker.

    To implement this, you must load the soljson binary and the solc/wrapper within the worker script, then communicate with the main thread using postMessage and addEventListener('message', ...).

    <!DOCTYPE html>
    <html>
    
    <head>
    	<meta charset="utf-8" />
    </head>
    
    <body
    	<script>
    		var worker = new Worker('./dist/bundle.js');
    		worker.addEventListener('message', function (e) {
    			console.log(e.data.version)
    		}, false);
    
    		worker.postMessage({})
    	</script>
    </body>
    
    </html>
  2. Configure Electron for `solc-js`

    master

    When using solc-js in Electron, if nodeIntegration is enabled for a BrowserWindow, the default require method may cause require('solc') to fail. To ensure compatibility, disable nodeIntegration in your window configuration.

    new BrowserWindow({
      webPreferences: {
        nodeIntegration: false
      }
    });
  3. Implement a solc Web Worker

    master

    When setting up a Web Worker for solc, use importScripts to load the specific soljson binary from the Solidity binaries repository, and import the wrapper from solc/wrapper. Inside the worker's message event listener, initialize the compiler using wrapper(self.Module) and send results back to the main thread via self.postMessage.

    importScripts('https://binaries.soliditylang.org/bin/soljson-v0.8.19+commit.7dd6d404.js')
    import wrapper from 'solc/wrapper';
    
    self.addEventListener('message', () => {
    	const compiler = wrapper(self.Module)
    	self.postMessage({
    		version: compiler.version()
    	})
    }, false)
  4. Use the `smtSolver` callback for SMTChecker

    master

    Since version 0.5.1, the smtSolver callback can be used to solve SMT queries generated by Solidity's SMTChecker. This requires a local SMT solver (like Z3, Eldarica, or cvc5) to be installed.

    Note: The SMT callback API is experimental and subject to change. This usage pattern is currently only supported in Node.js, not in the browser.

    var solc = require('solc');
    const smtchecker = require('solc/smtchecker');
    const smtsolver = require('solc/smtsolver');
    
    var input = {
      language: 'Solidity',
      sources: {
        'test.sol': {
          content: 'contract C { function f(uint x) public { assert(x > 0); } }'
        }
      },
      settings: {
        modelChecker: {
          engine: "chc",
          solvers: [ "smtlib2" ]
        }
      }
    };
    
    var output = JSON.parse(
      solc.compile(
        JSON.stringify(input),
        { smtSolver: smtchecker.smtCallback(smtsolver.smtSolver, smtsolver.availableSolvers[0]) }
      )
    );
  5. Understand the Low-level API

    master

    The low-level API provides direct access to specific compiler interfaces. While these remain available for compatibility, they are superseded by the high-level compile() function.

    Warning: For compilers version 0.5.0+commit.1d4f565a and newer, the following functions will always be null:

    • solc.lowlevel.compileSingle
    • solc.lowlevel.compileMulti
    • solc.lowlevel.compileCallback

    Available low-level methods:

    • solc.lowlevel.compileSingle: Supports only a single file.
    • solc.lowlevel.compileMulti: Supports multiple files (introduced in 0.1.6).
    • solc.lowlevel.compileCallback: Supports callbacks (introduced in 0.2.1).
    • solc.lowlevel.compileStandard: Works like the high-level compile() (available in 0.4.11+).
  6. Load a specific or remote Solidity version

    master

    You can load specific versions of the Solidity compiler using solc.loadRemoteVersion(version, callback).

    • To load the latest development snapshot, use 'latest' as the version.
    • To load a specific release, use the long format including the commit hash (e.g., 'v0.8.17+commit.8df45f5f'). You can find these strings in the official release list.

    Alternatively, you can manually load a local soljson.js file and use solc.setupMethods(soljson).

  7. Update old Solidity ABIs

    master

    Because new Solidity features can change the ABI structure, use the solc/abi module to translate ABIs generated by older versions to the latest standard.

    var abi = require('solc/abi');
    
    var inputABI = [
      {
        constant: false,
        inputs: [],
        name: 'hello',
        outputs: [{ name: '', type: 'string' }],
        payable: false,
        type: 'function'
      }
    ];
    
    // Update ABI from version '0.3.6' to current
    var outputABI = abi.update('0.3.6', inputABI);
  8. Use the High-level API with `compile()`

    master

    The high-level API provides a uniform interface across all compiler versions via the solc.compile() method. It expects a JSON string representing the Compiler Standard Input and Output.

    Starting from version 0.6.0, callbacks (like import and smtSolver) must be passed as an object in the second argument.

    var solc = require('solc');
    
    var input = {
      language: 'Solidity',
      sources: {
        'test.sol': {
          content: 'contract C { function f() public { } }'
        }
      },
      settings: {
        outputSelection: {
          '*': {
            '*': ['*']
          }
        }
      }
    };
    
    var output = JSON.parse(solc.compile(JSON.stringify(input)));
    
    // Accessing bytecode from output
    for (var contractName in output.contracts['test.sol']) {
      console.log(
        contractName +
          ': ' + 
          output.contracts['test.sol'][contractName].evm.bytecode.object
      );
    }
  9. Resolve dependencies with the `import` callback

    master

    The import callback allows you to resolve unmet dependencies in your Solidity files. The callback receives a path and must synchronously return either an error or the dependency content as a string.

    Note: Because it is synchronous, you cannot use asynchronous filesystem access directly within this callback. A common workaround is to collect dependency names, return an error, and re-run the compiler until all dependencies are resolved.

    var solc = require('solc');
    
    var input = {
      language: 'Solidity',
      sources: {
        'test.sol': {
          content: 'import "lib.sol"; contract C { function f() public { L.f(); } }'
        }
      },
      settings: {
        outputSelection: {
          '*': {
            '*': ['*']
          }
        }
      }
    };
    
    function findImports(path) {
      if (path === 'lib.sol')
        return {
          contents: 'library L { function f() internal returns (uint) { return 7; } }'
        };
      else return { error: 'File not found' };
    }
    
    // Syntax for 0.5.12+ (mandatory from 0.6.0)
    var output = JSON.parse(
      solc.compile(JSON.stringify(input), { import: findImports })
    );
  10. Link Bytecode for Libraries

    master

    When a contract uses libraries, the bytecode contains placeholders that must be updated with actual addresses via a process called linking.

    Use the solc/linker module to perform this task:

    • linker.linkBytecode(bytecode, { LibraryName: '0x...' }): A simple helper for linking.
    • linker.findLinkReferences(bytecode): Finds link references in bytecode produced by older compilers.